├── .github └── workflows │ ├── c-cpp.yml │ └── gnuplot_install.inf ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── example-3d.cpp ├── example-addpoint.cpp ├── example-animated-gif.cpp ├── example-complex.cpp ├── example-dumb.cpp ├── example-errorbars.cpp ├── example-histogram.cpp ├── example-multipleseries.cpp ├── example-pdfoutput.cpp ├── example-pngoutput.cpp ├── example-simple.cpp ├── example-vec.cpp ├── example-vec3d.cpp ├── gplot++.h ├── images ├── 3d.png ├── animation.gif ├── complex.png ├── dumb-terminal-example.png ├── errorbars.png ├── example-vec.png ├── histogram.png ├── multipleseries.png └── output.png └── tests ├── doctest.h └── run_tests.cpp /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Luca Cappa 2 | # Released under the term specified in file LICENSE.txt 3 | # SPDX short identifier: MIT 4 | 5 | # A GitHub workflow using CMake, Ninja and vcpkg. 6 | # It is called "pure" because it is an example which minimizes the usage of custom GitHub actions, but leverages directly the tools that could be easily run on your development machines (i.e. CMake, vcpkg, Ninja). 7 | name: hosted-pure-workflow 8 | on: [push] 9 | 10 | jobs: 11 | job: 12 | name: ${{ matrix.os }}-hosted-pure 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | os: [ubuntu-latest, macos-latest, windows-latest] 18 | include: 19 | - os: windows-latest 20 | triplet: x64-windows 21 | - os: ubuntu-latest 22 | triplet: x64-linux 23 | - os: macos-latest 24 | triplet: x64-osx 25 | env: 26 | # Indicates the CMake build directory where project files and binaries are being produced. 27 | CMAKE_BUILD_DIR: ${{ github.workspace }}/builddir/ 28 | 29 | steps: 30 | - uses: actions/checkout@v2 31 | with: 32 | submodules: true 33 | 34 | # Install Gnuplot. The way we do it depends on the system 35 | - name: Install Gnuplot for Linux 36 | if: runner.os == 'Linux' 37 | run: | 38 | sudo apt-get -o Acquire::Retries=3 -y update 39 | sudo apt-get -o Acquire::Retries=3 -y install gnuplot 40 | - name: Install Gnuplot for Mac OS X 41 | if: runner.os == 'macOS' 42 | run: | 43 | brew update 44 | brew install gnuplot 45 | - name: Install Gnuplot and MinGW for Windows 46 | if: runner.os == 'Windows' 47 | run: | 48 | choco install -y --no-progress gnuplot --install-arguments="/LOADINF=gnuplot_install.inf" 49 | choco install -y --no-progress mingw 50 | g++ --version 51 | 52 | # Setup the build machine with the most recent versions of CMake and Ninja. Both are cached if not already: on subsequent runs both will be quickly restored from GitHub cache service. 53 | - uses: lukka/get-cmake@latest 54 | 55 | - name: Generate project files 56 | run: | 57 | cmake -G Ninja -B "${{ env.CMAKE_BUILD_DIR }}" 58 | # Build the whole project 59 | - name: Build 60 | run: | 61 | cmake --build "${{ env.CMAKE_BUILD_DIR }}" 62 | # Run the tests 63 | - name: Run tests 64 | working-directory: "${{ env.CMAKE_BUILD_DIR }}" 65 | # Under Windows, Chocolatey does not put Gnuplot in the PATH and the tests fail 66 | if: runner.os != 'Windows' 67 | run: | 68 | ctest -C Debug --output-on-failure 69 | - name: Show content of workspace at its completion 70 | run: find $RUNNER_WORKSPACE 71 | shell: bash 72 | -------------------------------------------------------------------------------- /.github/workflows/gnuplot_install.inf: -------------------------------------------------------------------------------- 1 | [Setup] 2 | Lang=en 3 | Dir=C:\gnuplot 4 | Group=gnuplot 5 | NoIcons=0 6 | SetupType=full 7 | Components=core 8 | Tasks=defaulttermpreserve,modifypath 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | build/ 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | 6 | project(gplotpp 7 | VERSION 0.3.0 8 | DESCRIPTION "A C++ header-only interface to Gnuplot" 9 | LANGUAGES CXX 10 | ) 11 | 12 | enable_testing() 13 | 14 | add_test(NAME run_tests 15 | COMMAND run_tests 16 | ) 17 | 18 | add_executable(example-3d 19 | example-3d.cpp 20 | ) 21 | 22 | add_executable(example-addpoint 23 | example-addpoint.cpp 24 | ) 25 | 26 | add_executable(example-animated-gif 27 | example-animated-gif.cpp 28 | ) 29 | 30 | add_executable(example-complex 31 | example-complex.cpp 32 | ) 33 | 34 | add_executable(example-errorbars 35 | example-errorbars.cpp 36 | ) 37 | 38 | add_executable(example-histogram 39 | example-histogram.cpp 40 | ) 41 | 42 | add_executable(example-multipleseries 43 | example-multipleseries.cpp 44 | ) 45 | 46 | add_executable(example-pdfoutput 47 | example-pdfoutput.cpp 48 | ) 49 | 50 | add_executable(example-pngoutput 51 | example-pngoutput.cpp 52 | ) 53 | 54 | add_executable(example-simple 55 | example-simple.cpp 56 | ) 57 | 58 | add_executable(example-vec 59 | example-vec.cpp 60 | ) 61 | 62 | add_executable(example-vec3d 63 | example-vec3d.cpp 64 | ) 65 | 66 | add_executable(example-dumb 67 | example-dumb.cpp 68 | ) 69 | 70 | add_executable(run_tests 71 | tests/run_tests.cpp 72 | ) 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Maurizio Tomasi (maurizio.tomasi@unimi.it) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gplot++ 2 | 3 | [![](https://github.com/ziotom78/gplotpp/workflows/make-checks/badge.svg)](https://github.com/ziotom78/gplotpp/actions?query=workflow%3Amake-checks) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 5 | 6 | A header-only C++ interface to Gnuplot. See [this video](https://vimeo.com/638098854) for a demo (running Visual Studio under Windows 10). 7 | 8 | This repository contains the file [gplot++.h](https://raw.githubusercontent.com/ziotom78/gplotpp/master/gplot%2B%2B.h), which provides a way for C++ programs to connect to a Gnuplot instance to produce plots. To use this library, you must first install [Gnuplot](http://www.gnuplot.info/) on your system! 9 | 10 | A few features of this library are the following: 11 | 12 | - Header-only library: very easy to install 13 | - Plot `std::vector` variables 14 | - Multiple series in the same plot 15 | - Multiple plots (via `Gnuplot::multiplot`) 16 | - Logarithmic axes (via `Gnuplot::set_logscale`) 17 | - Histograms (via `Gnuplot::histogram`) 18 | - Custom ranges (via `Gnuplot::set_xrange` and `Gnuplot::set_yrange`) 19 | - Possibility to save the plots in PNG and PDF files 20 | - 3D plots (**new in 0.2.0**) 21 | 22 | 23 | # Table of Contents 24 | 25 | * [gplot++](#gplot) 26 | * [Table of Contents](#table-of-contents) 27 | * [Installing Gnuplot and gplot++.h](#installing-gnuplot-and-gploth) 28 | * [Windows](#windows) 29 | * [Linux](#linux) 30 | * [Mac OS X](#mac-os-x) 31 | * [Installing gplot++.h](#installing-gploth) 32 | * [Examples](#examples) 33 | * [Documentation](#documentation) 34 | * [Initializing a connection to Gnuplot](#initializing-a-connection-to-gnuplot) 35 | * [Plot commands](#plot-commands) 36 | * [Histograms](#histograms) 37 | * [Line styles](#line-styles) 38 | * [Styling the plot axes](#styling-the-plot-axes) 39 | * [Logarithmic scale](#logarithmic-scale) 40 | * [Multiple plots](#multiple-plots) 41 | * [Error bars](#error-bars) 42 | * [3D plots](#3d-plots) 43 | * [Vector fields](#vector-fields) 44 | * [Saving plots to a file](#saving-plots-to-a-file) 45 | * [Animations](#animations) 46 | * [Low-level interface](#low-level-interface) 47 | * [Similar libraries](#similar-libraries) 48 | * [Changelog](#changelog) 49 | * [HEAD](#head) 50 | * [v0.5.1](#v051) 51 | * [v0.5.0](#v050) 52 | * [v0.4.0](#v040) 53 | * [v0.3.1](#v031) 54 | * [v0.3.0](#v030) 55 | * [v0.2.1](#v021) 56 | * [v0.2.0](#v020) 57 | * [v0.1.0](#v010) 58 | 59 | Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) 60 | 61 | 62 | ## Installing Gnuplot and `gplot++.h` 63 | 64 | Of course, before using `gplot++.h` you must have Gnuplot installed and available in the `PATH`! We provide here instructions about how to install Gnuplot under Windows, Mac OS X, and Linux. 65 | 66 | **Windows users, beware that the standard installation won't work with `gplot++.h` because you need to activate a flag during the installation!** 67 | 68 | ### Windows 69 | 70 | Download the Gnuplot installer from the [SourceForge website](https://sourceforge.net/projects/gnuplot/files/gnuplot/). Be sure not to download the `.tar.gz` file; instead, you should download the file ending with `.exe`, e.g., [gp542-win64-mingw.exe](https://sourceforge.net/projects/gnuplot/files/gnuplot/5.4.2/gp542-win64-mingw.exe/download). 71 | 72 | When you run the installer, pay attention to the option *Add application directory to your PATH environment variable* while installing Gnuplot, otherwise **`gplot++.h` will fail to generate the plots**! See [this video](https://vimeo.com/638098416) for help. 73 | 74 | ### Linux 75 | 76 | Linux users should use their package manager to install Gnuplot: 77 | 78 | # Debian, Ubuntu, Linux Mint 79 | sudo apt-get install gnuplot 80 | 81 | # Arch, Manjaro 82 | sudo pacman -Syu gnuplot 83 | 84 | # Fedora 85 | sudo dns install gnuplot 86 | 87 | ### Mac OS X 88 | 89 | The preferred way to install Gnuplot is using [Homebrew](https://formulae.brew.sh/formula/gnuplot) from the terminal: 90 | 91 | brew install gnuplot 92 | 93 | ### Installing `gplot++.h` 94 | 95 | Once you have Gnuplot installed, download the file [gplot++.h](https://raw.githubusercontent.com/ziotom78/gplotpp/master/gplot%2B%2B.h) and save it in the same folder as your program. That's all. 96 | 97 | [This video](https://vimeo.com/638098854) shows how to include [gplot++.h](https://raw.githubusercontent.com/ziotom78/gplotpp/master/gplot%2B%2B.h) in a C++ project created using Visual Studio 2019 (Windows). 98 | 99 | ## Examples 100 | 101 | Here is the output of one of the examples: 102 | 103 | ![](./images/complex.png) 104 | 105 | The source code of the example is in file `example-complex.cpp`: 106 | 107 | ```c++ 108 | #include "gplot++.h" 109 | 110 | int main(void) { 111 | Gnuplot plt{}; 112 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 113 | 114 | // Save the plot into a PNG file with the desired size (in pixels) 115 | plt.redirect_to_png("complex.png", "800,600"); 116 | 117 | /* Create two plots with the following layout (2 rows, 1 column): 118 | * 119 | * +------------------------+ 120 | * | | 121 | * | Plot #1 | 122 | * | | 123 | * +------------------------+ 124 | * | | 125 | * | Plot #2 | 126 | * | | 127 | * +------------------------+ 128 | */ 129 | plt.multiplot(2, 1, "Title"); 130 | 131 | // Plot #1 132 | plt.set_title("Plot #1"); 133 | plt.set_xlabel("X axis"); 134 | plt.set_ylabel("Y axis"); 135 | plt.plot(x, y, "x-y plot"); 136 | plt.plot(y, x, "y-x plot", Gnuplot::LineStyle::LINESPOINTS); 137 | plt.show(); // Always call "show"! 138 | 139 | // Plot #2 140 | plt.set_title("Plot #2"); 141 | plt.set_xlabel("Value"); 142 | plt.set_ylabel("Number of counts"); 143 | plt.histogram(y, 2, "Histogram"); 144 | plt.set_xrange(-1, 7); 145 | plt.set_yrange(0, 5); 146 | plt.show(); // Always call "show"! 147 | } 148 | ``` 149 | 150 | ## Documentation 151 | 152 | ### Initializing a connection to Gnuplot 153 | 154 | The only symbol exported by file `gplot++.h` is the `Gnuplot` class. When you instance an object of this class, it will silently start `gnuplot` in the background and open a pipe through it: 155 | 156 | ```c++ 157 | #include "gplot++.h" 158 | 159 | int main() { 160 | Gnuplot plt{}; 161 | 162 | // ... 163 | } 164 | ``` 165 | 166 | If Gnuplot is not available in your `PATH` (probably this is most common on Windows system), you can specify the full path to the executable: 167 | 168 | ```c++ 169 | #include "gplot++.h" 170 | 171 | int main() { 172 | Gnuplot plt{R"(C:\Program Files\Gnuplot\gnuplot.exe)"}; 173 | 174 | // ... 175 | } 176 | ``` 177 | 178 | The connection will be automatically closed once the variable `plt` goes out of scope; by default, the Gnuplot window will be left open. In this way, you can navigate through the Gnuplot window even after your C++ has completed its execution. 179 | 180 | ### Plot commands 181 | 182 | There are two ways to produce a plot; both require you to call the `Gnuplot::plot` method: 183 | 184 | 1. Pass one `std::vector` variable, which will be used to set the `y` coordinates of the points; 185 | 2. Pass two `std::vector` variables; these will be used to set the `(x, y)` coordinates of the points. 186 | 187 | You can call `plot` multiple times, and each time your call will be recorded in a list. When you are ready to produce a plot, call `Gnuplot::show`, like in the following example: 188 | 189 | several ways to produce a plot. Each of them requires you to pass the data to plot through one or more `std::vector` variables: 190 | 191 | ```c++ 192 | std::vector x{1, 2, 4}; // No problem to use a vector of ints 193 | std::vector y1{3.1, -4.6, 5.1}; 194 | std::vector y2{1.3, 1.6, 4.1}; 195 | 196 | Gnuplot plt{}; 197 | // Just pass the set of y values 198 | plt.plot(y1); 199 | 200 | // You can provide a label and a linestyle 201 | plt.plot(x, y2, "Dataset #1", Gnuplot::LineStyle::LINESPOINTS); 202 | 203 | // Now produce the plot 204 | plt.show(); 205 | ``` 206 | 207 | ![](images/multipleseries.png) 208 | 209 | **New in version 0.7.0**: Instead of providing the two vectors, you can call `Gnuplot::add_point()` repeatedly and then call `Gnuplot::plot()` without specifying vectors. See the example program [example-addpoint.cpp](https://github.com/ziotom78/gplotpp/blob/master/example-addpoint.cpp). 210 | 211 | 212 | ### Histograms 213 | 214 | Gplot++ implements the method `Gnuplot::histogram`, which computes the histogram of a series and plot it using Gnuplot. Here is an example (`example-histogram.cpp`): 215 | 216 | ```c++ 217 | #include "gplot++.h" 218 | 219 | int main(void) { 220 | Gnuplot gnuplot{}; 221 | std::vector y{5, 2, 4, 1, 3}; 222 | 223 | gnuplot.histogram(y, 2, "Histogram"); 224 | 225 | gnuplot.set_xlabel("Value"); 226 | gnuplot.set_ylabel("Number of counts"); 227 | gnuplot.set_xrange(1, 5); 228 | gnuplot.set_yrange(0, 5); 229 | 230 | gnuplot.show(); 231 | } 232 | ``` 233 | 234 | ![](images/histogram.png) 235 | 236 | The parameters to `Gnuplot::histogram` are the following: 237 | 238 | - A vector containing the values to use in the plot; 239 | 240 | - The number of bins to plot (two bins in the example above); 241 | 242 | - A label for the plot (optional, default is empty) 243 | 244 | - The line style (optional, default is `Gnuplot::LineStyle::BOXES`) 245 | 246 | 247 | ### Line styles 248 | 249 | There are several line styles: 250 | 251 | - `Gnuplot::LineStyle::DOTS` (only use this when you have many points); 252 | 253 | - `Gnuplot::LineStyle::LINES` (the default); 254 | 255 | - `Gnuplot::LineStyle::POINTS`; 256 | 257 | - `Gnuplot::LineStyle::LINESPOINTS`; 258 | 259 | - `Gnuplot::LineStyle::STEPS`; 260 | 261 | - `Gnuplot::LineStyle::BOXES` (only used for histograms). 262 | 263 | - `Gnuplot::LineStyle::VECTORS` (only used for 2D and 3D vector fields). 264 | 265 | 266 | ### Styling the plot axes 267 | 268 | You can manually assign a range to the X and Y axes using the methods `Gnuplot::set_xlabel` and `Gnuplot::set_ylabel`: 269 | 270 | ```c++ 271 | Gnuplot plt{}; 272 | 273 | plt.set_xrange(1.5, 3.5); 274 | plt.set_yrange(); // No parameters means automatic axes 275 | ``` 276 | 277 | If you are creating multiple plots (see below), you should probably reset the x and y ranges after each call to `Gnuplot::show`. 278 | 279 | You can also provide a label for both axes: 280 | 281 | ```c++ 282 | plt.set_xlabel("Time [s]"); 283 | plt.set_ylabel("Speed [cm/s]"); 284 | ``` 285 | 286 | ### Logarithmic scale 287 | 288 | To set a logarithmic scale, use `Gnuplot::set_logscale`: 289 | 290 | ```c++ 291 | Gnuplot plt{}; 292 | 293 | plt.set_logscale(Gnuplot::AxisScale::LOGXY); 294 | ``` 295 | 296 | Possible parameters are: 297 | 298 | - `Gnuplot::AxisScale::LINEAR` (the default); 299 | - `Gnuplot::AxisScale::LOGX`; 300 | - `Gnuplot::AxisScale::LOGY`; 301 | - `Gnuplot::AxisScale::LOGXY`. 302 | 303 | 304 | ### Multiple plots 305 | 306 | You can make several plots within the same window using the method `Gnuplot::multiplot`. It accepts the following parameters: 307 | 308 | - The number of rows to use; 309 | 310 | - The number of columns to use; 311 | 312 | - A title (optional, default is no title). 313 | 314 | You must paint the several plot in order, and each time you complete one plot you must call `Gnuplot::show`. 315 | 316 | 317 | ### Error bars 318 | 319 | Starting from version 0.3.1, `gplot++.h` supports plots with error bars through these functions: 320 | 321 | ```c++ 322 | Gnuplot::plot_xerr(x, y, xerr, label = ""); 323 | Gnuplot::plot_yerr(x, y, yerr, label = ""); 324 | Gnuplot::plot_xyerr(x, y, xerr, yerr, label = ""); 325 | ``` 326 | 327 | Here is an example ([example-errorbars.cpp](./example-errorbars.cpp)): 328 | 329 | ```c++ 330 | #include "gplot++.h" 331 | 332 | int main(void) { 333 | Gnuplot plt{}; 334 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 335 | std::vector xerr{0.2, 0.2, 0.1, 0.1, 0.2}, 336 | yerr{0.3, 0.4, 0.2, 0.6, 0.7}; 337 | 338 | /* Create four plots with the following layout (2 rows, 2 columns): 339 | * 340 | * +------------------------+------------------------+ 341 | * | | | 342 | * | Plot #1 | Plot #2 | 343 | * | | | 344 | * +------------------------+------------------------+ 345 | * | | | 346 | * | Plot #3 | Plot #4 | 347 | * | | | 348 | * +------------------------+------------------------+ 349 | */ 350 | plt.multiplot(2, 2, "Title"); 351 | 352 | // Plot #1 353 | plt.set_xlabel("X axis"); 354 | plt.set_ylabel("Y axis"); 355 | plt.plot(x, y, "", Gnuplot::LineStyle::POINTS); 356 | plt.show(); // Always call "show"! 357 | 358 | // Plot #2: X error bar 359 | plt.set_xlabel("X axis"); 360 | plt.set_ylabel("Y axis"); 361 | plt.plot_xerr(x, y, xerr); 362 | plt.show(); // Always call "show"! 363 | 364 | // Plot #3: Y error bar 365 | plt.set_xlabel("X axis"); 366 | plt.set_ylabel("Y axis"); 367 | plt.plot_yerr(x, y, yerr); 368 | plt.show(); // Always call "show"! 369 | 370 | // Plot #4: X and Y error bars 371 | plt.set_xlabel("X axis"); 372 | plt.set_ylabel("Y axis"); 373 | plt.plot_xyerr(x, y, xerr, yerr); 374 | plt.show(); // Always call "show"! 375 | } 376 | ``` 377 | 378 | ![](./images/errorbars.png) 379 | 380 | ### 3D plots 381 | 382 | You can create 3D plots using the command `plot3d`, which takes *three* vectors. See the file `example-3d.cpp`: 383 | 384 | ```c++ 385 | #include "gplot++.h" 386 | #include 387 | #include 388 | 389 | int main(void) { 390 | Gnuplot gnuplot{}; 391 | std::vector x, y, z; 392 | 393 | for (double angle = 0; angle < 6 * M_PI; angle += 0.1) { 394 | x.push_back(cos(angle)); 395 | y.push_back(sin(angle)); 396 | z.push_back(angle / 2 * M_PI); 397 | } 398 | 399 | gnuplot.plot3d(x, y, z); 400 | gnuplot.show(); 401 | } 402 | ``` 403 | 404 | Here is the result: 405 | 406 | ![](./images/3d.png) 407 | 408 | 409 | ### Vector fields 410 | 411 | Starting from version 0.4.0, gplot++ supports vector field plots, both in 2D and 3D, through the methods `Gnuplot::plot_vectors` and `Gnuplot::plot_vectors3d`: 412 | 413 | ```c++ 414 | #include "gplot++.h" 415 | #include 416 | #include 417 | 418 | using namespace std; 419 | 420 | int main(void) { 421 | Gnuplot gnuplot{}; 422 | 423 | vector x{}, y{}; 424 | vector vx{}, vy{}; 425 | 426 | // Sample a regular grid. Use a small tilt to avoid sampling 427 | // the grid at the origin 428 | for (double cur_x{-10.1}; cur_x <= 10; cur_x += 1) { 429 | for (double cur_y{-10.1}; cur_y <= 10; cur_y += 1) { 430 | x.push_back(cur_x); 431 | y.push_back(cur_y); 432 | 433 | double r{sqrt(pow(cur_x, 2) + pow(cur_y, 2))}; 434 | double cur_vx{-cur_x / r}; 435 | double cur_vy{-cur_y / r}; 436 | vx.push_back(cur_vx); 437 | vy.push_back(cur_vy); 438 | } 439 | } 440 | 441 | gnuplot.plot_vectors(x, y, vx, vy); 442 | gnuplot.show(); 443 | } 444 | ``` 445 | 446 | ![](./images/example-vec.png) 447 | 448 | 449 | ### Saving plots to a file 450 | 451 | It is often useful to save the plot into a file, instead of opening a window. You can save plots in PNG format if you call the method `Gnuplot::redirect_to_png`: 452 | 453 | ```c++ 454 | Gnuplot plt{}; 455 | 456 | // Call this immediately after you constructed the object "plt" 457 | plt.redirect_to_png("image.png", "800,600"); 458 | ``` 459 | 460 | The first parameter is the name of the image file to create, and the second is a string specifying the size of the image, in the format `width,height` (in pixels). If you avoid passing the second parameter, a sensible default will be used: 461 | 462 | ```c++ 463 | Gnuplot plt{}; 464 | 465 | // Use the default size 466 | plt.redirect_to_png("image.png"); 467 | ``` 468 | 469 | You can save the plot in a PDF file, which should be the preferred format if you plan to include the plot in a LaTeX document: 470 | 471 | ```c++ 472 | Gnuplot plt{}; 473 | 474 | // Call this immediately after you constructed the object "plt" 475 | plt.redirect_to_pdf("image.pdf", "20cm,15cm"); 476 | ``` 477 | 478 | Unlike `Gnuplot::redirect_to_png`, when you create a PDF file you can use several measure units to specify the size of the image. In this case too, you can avoid passing the second parameter, and a reasonable default will be used. 479 | 480 | You can save the plot in a SVG file via the method `Gnuplot::redirect_to_svg`. In this case, the SVG file will be interactive when opened in a web browser. 481 | 482 | Finally, you can use `Gnuplot::redirect_to_dumb` to send the plot to the terminal or to a text file. You can pass a `Gnuplot::TerminalMode` value to specify if you want to include ANSI escape codes to produce colors, as shown in [`example-dumb.cpp`](example-dumb.cpp): 483 | 484 | ![](images/dumb-terminal-example.png) 485 | 486 | ### Animations 487 | 488 | You can plot animations interactively by simply running a `for` loop and adding a delay before plotting the next frame. A better solution is to create an animated GIF file using `Gnuplot::redirect_to_animated_gif`: 489 | 490 | ```c++ 491 | int main(void) { 492 | Gnuplot gnuplot{}; 493 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 494 | 495 | std::cout << "Running gplot++ v" << GNUPLOTPP_MAJOR_VERSION << "." 496 | << GNUPLOTPP_MINOR_VERSION << "." << GNUPLOTPP_PATCH_VERSION 497 | << "\n"; 498 | 499 | gnuplot.redirect_to_animated_gif("animation.gif", "800,600", 1000, true); 500 | 501 | for(int i{}; i < (int) x.size(); ++i) { 502 | gnuplot.add_point(x[i], y[i]); 503 | gnuplot.plot(); // Do the plot 504 | 505 | // In an animation, it is advisable to force the x/y ranges in advance 506 | gnuplot.set_xrange(0, 6); 507 | gnuplot.set_yrange(0, 6); 508 | 509 | gnuplot.show(); // Add the frame to the GIF file 510 | } 511 | 512 | gnuplot.show(); 513 | 514 | std::cout << "Press any key to quit..."; 515 | std::getchar(); 516 | } 517 | ``` 518 | 519 | Here is the result: 520 | 521 | ![](images/animation.gif) 522 | 523 | ### Low-level interface 524 | 525 | You can pass commands to Gnuplot using the method `Gnuplot::sendcommand`: 526 | 527 | ```c++ 528 | Gnuplot plt{}; 529 | 530 | plt.sendcommand("set xlabel 'X axis'"); 531 | plt.sendcommand("plot sin(x)"); 532 | ``` 533 | 534 | ## Similar libraries 535 | 536 | There are several other libraries like gplot++ around. These are the ones I referenced while developing my own's: 537 | 538 | - [gnuplot-iostream](https://github.com/dstahlke/gnuplot-iostream): it has much more features than gplot++, but it is slightly more difficult to install and use. 539 | - [gnuplot-cpp](https://github.com/martinruenz/gnuplot-cpp): another header-only library. It lacks support for high-level stuff like `std::vector` plotting. 540 | 541 | ## Changelog 542 | 543 | ### HEAD 544 | 545 | ### 0.9.1 546 | 547 | - Bug fixes in method `histogram` (see PR [#15](https://github.com/ziotom78/gplotpp/pull/15)) 548 | 549 | ### 0.9.0 550 | 551 | - New method `redirect_to_animated_gif` 552 | 553 | ### v0.8.0 554 | 555 | - New methods `add_point_xerr`, `add_point_yerr`, and `add_point_xyerr`, and new overloads for functions `plot_xerr`, `plot_yerr`, `plot_xyerr` 556 | 557 | ### v0.7.0 558 | 559 | - Add `Gnuplot::add_point`, `Gnuplot::get_num_of_points()`, `Gnuplot::get_points_x()`, and `Gnuplot::get_points_y()`, as well as a new overloaded method `Gnuplot::plot()` which does not require the vectors of `x` and `y`. 560 | 561 | ### v0.5.1 (a.k.a. 0.6.0) 562 | 563 | - Add `Gnuplot::set_title` 564 | 565 | ### v0.5.0 566 | 567 | - Add `redirect_to_dumb` and the `TerminalType` enum class to support the `dumb` terminal 568 | 569 | - Use a smarter algorithm to specify ranges in `Gnuplot.set_xrange` and `Gnuplot.set_yrange`: now specifying one of the two extrema as `NAN` does not override the specification of the other. 570 | 571 | ### v0.4.0 572 | 573 | - `Gnuplot::redirect_to_svg` has been added 574 | 575 | - `Gnuplot::plot_vectors`, `Gnuplot::plot_vectors3d` have been added 576 | 577 | ### v0.3.1 578 | 579 | - `Gnuplot::plot_xerr`, `Gnuplot::plot_yerr`, and `Gnuplot::plot_xyerr` have been added 580 | 581 | ### v0.3.0 582 | 583 | - The library is now supported under Windows 584 | 585 | ### v0.2.1 586 | 587 | - Ensure that commands sent to Gnuplot are executed immediately ([#1](https://github.com/ziotom78/gplotpp/pull/1)) 588 | 589 | ### v0.2.0 590 | 591 | - New constants `GNUPLOTPP_VERSION`, `GNUPLOTPP_MAJOR_VERSION`, `GNUPLOTPP_MINOR_VERSION`, and `GNUPLOTPP_PATCH_VERSION` 592 | 593 | - 3D plots (after a suggestion by William Luciani) 594 | 595 | ### v0.1.0 596 | 597 | - First release 598 | -------------------------------------------------------------------------------- /example-3d.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | const double pi{3.1415926535897932384626433}; 29 | 30 | int main(void) { 31 | Gnuplot gnuplot{}; 32 | std::vector x, y, z; 33 | 34 | for (double angle = 0; angle < 6 * pi; angle += 0.1) { 35 | x.push_back(cos(angle)); 36 | y.push_back(sin(angle)); 37 | z.push_back(angle / 2 * pi); 38 | } 39 | 40 | gnuplot.plot3d(x, y, z); 41 | gnuplot.show(); 42 | } 43 | -------------------------------------------------------------------------------- /example-addpoint.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2023 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | int main(void) { 29 | Gnuplot gnuplot{}; 30 | 31 | std::cout << "Running gplot++ v" << GNUPLOTPP_MAJOR_VERSION << "." 32 | << GNUPLOTPP_MINOR_VERSION << "." << GNUPLOTPP_PATCH_VERSION 33 | << "\n"; 34 | 35 | for(int k{}; k < 12; ++k) { 36 | gnuplot.add_point(0.5 * k * k); 37 | } 38 | gnuplot.plot("", Gnuplot::LineStyle::LINESPOINTS); 39 | gnuplot.show(); 40 | 41 | std::cout << "Press any key to quit..."; 42 | std::getchar(); 43 | } 44 | -------------------------------------------------------------------------------- /example-animated-gif.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | int main(void) { 29 | Gnuplot gnuplot{}; 30 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 31 | 32 | std::cout << "Running gplot++ v" << GNUPLOTPP_MAJOR_VERSION << "." 33 | << GNUPLOTPP_MINOR_VERSION << "." << GNUPLOTPP_PATCH_VERSION 34 | << "\n"; 35 | 36 | gnuplot.redirect_to_animated_gif("animation.gif", "800,600", 1000, true); 37 | 38 | for(int i{}; i < (int) x.size(); ++i) { 39 | gnuplot.add_point(x[i], y[i]); 40 | gnuplot.plot(); // Do the plot 41 | 42 | // In an animation, it is advisable to force the x/y ranges in advance 43 | gnuplot.set_xrange(0, 6); 44 | gnuplot.set_yrange(0, 6); 45 | 46 | gnuplot.show(); // Add the frame to the GIF file 47 | } 48 | 49 | gnuplot.show(); 50 | 51 | std::cout << "Press any key to quit..."; 52 | std::getchar(); 53 | } 54 | -------------------------------------------------------------------------------- /example-complex.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | 26 | int main(void) { 27 | Gnuplot plt{}; 28 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 29 | 30 | // Save the plot into a PNG file with the desired size (in pixels) 31 | plt.redirect_to_png("complex.png", "800,600"); 32 | 33 | /* Create two plots with the following layout (2 rows, 1 column): 34 | * 35 | * +------------------------+ 36 | * | | 37 | * | Plot #1 | 38 | * | | 39 | * +------------------------+ 40 | * | | 41 | * | Plot #2 | 42 | * | | 43 | * +------------------------+ 44 | */ 45 | plt.multiplot(2, 1, "Title"); 46 | 47 | // Plot #1 48 | plt.set_xlabel("X axis"); 49 | plt.set_ylabel("Y axis"); 50 | plt.plot(x, y, "x-y plot"); 51 | plt.plot(y, x, "y-x plot", Gnuplot::LineStyle::LINESPOINTS); 52 | plt.show(); // Always call "show"! 53 | 54 | // Plot #2 55 | plt.set_xlabel("Value"); 56 | plt.set_ylabel("Number of counts"); 57 | plt.histogram(y, 2, "Histogram"); 58 | plt.set_xrange(-1, 7); 59 | plt.set_yrange(0, 5); 60 | plt.show(); // Always call "show"! 61 | } 62 | -------------------------------------------------------------------------------- /example-dumb.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | int main(void) { 29 | Gnuplot gnuplot{}; 30 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 31 | 32 | gnuplot.redirect_to_dumb("", 40, 20, Gnuplot::TerminalMode::ANSI); 33 | gnuplot.plot(x, y); 34 | gnuplot.show(); 35 | } 36 | -------------------------------------------------------------------------------- /example-errorbars.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | 26 | int main(void) { 27 | Gnuplot plt{}; 28 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 29 | std::vector xerr{0.2, 0.2, 0.1, 0.1, 0.2}, 30 | yerr{0.3, 0.4, 0.2, 0.6, 0.7}; 31 | 32 | // Save the plot into a PNG file with the desired size (in pixels) 33 | plt.redirect_to_png("errorbars.png", "800,600"); 34 | 35 | /* Create four plots with the following layout (2 rows, 2 columns): 36 | * 37 | * +------------------------+------------------------+ 38 | * | | | 39 | * | Plot #1 | Plot #2 | 40 | * | | | 41 | * +------------------------+------------------------+ 42 | * | | | 43 | * | Plot #3 | Plot #4 | 44 | * | | | 45 | * +------------------------+------------------------+ 46 | */ 47 | plt.multiplot(2, 2, "Title"); 48 | 49 | // Plot #1 50 | plt.set_xlabel("X axis"); 51 | plt.set_ylabel("Y axis"); 52 | plt.plot(x, y, "", Gnuplot::LineStyle::POINTS); 53 | plt.show(); // Always call "show"! 54 | 55 | // Plot #2: X error bar 56 | plt.set_xlabel("X axis"); 57 | plt.set_ylabel("Y axis"); 58 | plt.plot_xerr(x, y, xerr); 59 | plt.show(); // Always call "show"! 60 | 61 | // Plot #3: Y error bar 62 | plt.set_xlabel("X axis"); 63 | plt.set_ylabel("Y axis"); 64 | plt.plot_yerr(x, y, yerr); 65 | plt.show(); // Always call "show"! 66 | 67 | // Plot #4: X and Y error bars 68 | plt.set_xlabel("X axis"); 69 | plt.set_ylabel("Y axis"); 70 | plt.plot_xyerr(x, y, xerr, yerr); 71 | plt.show(); // Always call "show"! 72 | } 73 | -------------------------------------------------------------------------------- /example-histogram.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | 26 | int main(void) { 27 | Gnuplot gnuplot{}; 28 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 29 | 30 | gnuplot.histogram(y, 2, "Histogram"); 31 | 32 | gnuplot.set_xlabel("Value"); 33 | gnuplot.set_ylabel("Number of counts"); 34 | gnuplot.set_xrange(1, 5); 35 | gnuplot.set_yrange(0, 5); 36 | 37 | gnuplot.show(); 38 | } 39 | -------------------------------------------------------------------------------- /example-multipleseries.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | 27 | int main(void) { 28 | std::vector x{1, 2, 4}; // No problem to use a vector of ints 29 | std::vector y1{3.1, -4.6, 5.1}; 30 | std::vector y2{1.3, 1.6, 4.1}; 31 | 32 | Gnuplot plt{}; 33 | // Just pass the set of y values 34 | plt.plot(y1); 35 | 36 | // You can provide a label and a linestyle 37 | plt.plot(x, y2, "Dataset #1", Gnuplot::LineStyle::LINESPOINTS); 38 | 39 | // Now produce the plot 40 | plt.show(); 41 | } 42 | -------------------------------------------------------------------------------- /example-pdfoutput.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | 27 | int main(void) { 28 | Gnuplot gnuplot{}; 29 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 30 | 31 | gnuplot.redirect_to_pdf("output.pdf", "16cm,8cm"); 32 | 33 | gnuplot.plot(x, y); 34 | gnuplot.show(); 35 | } 36 | -------------------------------------------------------------------------------- /example-pngoutput.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | 27 | int main(void) { 28 | Gnuplot gnuplot{}; 29 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 30 | 31 | gnuplot.redirect_to_png("output.png", "800,600"); 32 | 33 | gnuplot.plot(x, y); 34 | gnuplot.show(); 35 | } 36 | -------------------------------------------------------------------------------- /example-simple.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | int main(void) { 29 | Gnuplot gnuplot{}; 30 | std::vector x{1, 2, 3, 4, 5}, y{5, 2, 4, 1, 3}; 31 | 32 | std::cout << "Running gplot++ v" << GNUPLOTPP_MAJOR_VERSION << "." 33 | << GNUPLOTPP_MINOR_VERSION << "." << GNUPLOTPP_PATCH_VERSION 34 | << "\n"; 35 | gnuplot.plot(x, y); 36 | gnuplot.show(); 37 | 38 | std::cout << "Press any key to quit..."; 39 | std::getchar(); 40 | } 41 | -------------------------------------------------------------------------------- /example-vec.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | int main(void) { 31 | Gnuplot gnuplot{}; 32 | 33 | vector x{}, y{}; 34 | vector vx{}, vy{}; 35 | 36 | // Sample a regular grid. Use a small tilt to avoid sampling 37 | // the grid at the origin 38 | for (double cur_x{-10.1}; cur_x <= 10; cur_x += 1) { 39 | for (double cur_y{-10.1}; cur_y <= 10; cur_y += 1) { 40 | x.push_back(cur_x); 41 | y.push_back(cur_y); 42 | 43 | double r{sqrt(pow(cur_x, 2) + pow(cur_y, 2))}; 44 | double cur_vx{-cur_x / r}; 45 | double cur_vy{-cur_y / r}; 46 | vx.push_back(cur_vx); 47 | vy.push_back(cur_vy); 48 | } 49 | } 50 | 51 | gnuplot.redirect_to_png("example-vec.png"); 52 | gnuplot.plot_vectors(x, y, vx, vy); 53 | gnuplot.show(); 54 | } 55 | -------------------------------------------------------------------------------- /example-vec3d.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 Maurizio Tomasi 2 | * 3 | * Permission is hereby granted, free of charge, to any person 4 | * obtaining a copy of this software and associated documentation 5 | * files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, 7 | * modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "gplot++.h" 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | int main(void) { 31 | Gnuplot gnuplot{}; 32 | 33 | vector x{}, y{}, z{}; 34 | vector vx{}, vy{}, vz{}; 35 | 36 | // Sample a regular grid. Use a small tilt to avoid sampling 37 | // the grid at the origin 38 | for (double cur_x{-10.1}; cur_x <= 10; cur_x += 2) { 39 | for (double cur_y{-10.1}; cur_y <= 10; cur_y += 2) { 40 | for (double cur_z{-10.1}; cur_z <= 10; cur_z += 2) { 41 | x.push_back(cur_x); 42 | y.push_back(cur_y); 43 | z.push_back(cur_z); 44 | 45 | double r{sqrt(pow(cur_x, 2) + pow(cur_y, 2))}; 46 | double cur_vx{-cur_x / r}; 47 | double cur_vy{-cur_y / r}; 48 | double cur_vz{-cur_z / r}; 49 | vx.push_back(cur_vx); 50 | vy.push_back(cur_vy); 51 | vz.push_back(cur_vz); 52 | } 53 | } 54 | } 55 | 56 | gnuplot.redirect_to_png("example-vec3d.png"); 57 | gnuplot.plot_vectors3d(x, y, z, vx, vy, vz); 58 | gnuplot.set_xrange(-10, 10); 59 | gnuplot.set_yrange(-10, 10); 60 | gnuplot.set_zrange(-10, 10); 61 | gnuplot.show(); 62 | } 63 | -------------------------------------------------------------------------------- /gplot++.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* gplot++ 4 | * 5 | * A header-only C++ interface to Gnuplot. 6 | * 7 | * Copyright 2020 Maurizio Tomasi 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | * Version history 30 | * 31 | * - 0.9.1 (2025/02/06): bug fixes in method `histogram` 32 | * 33 | * - 0.9.0 (2024/11/19): new method `redirect_to_animated_gif` 34 | * 35 | * - 0.8.0 (2024/10/15): new methods `add_point_xerr`, 36 | * `add_point_yerr`, and `add_point_xyerr`, 37 | * and new overloads for functions 38 | * `plot_xerr`, `plot_yerr`, `plot_xyerr` 39 | * 40 | * - 0.7.0 (2023/11/27): new methods `add_point` 41 | * 42 | * - 0.6.0 (2023/01/26): new method `set_title` 43 | * 44 | * - 0.5.0 (2021/12/02): use a smarter algorithm to specify ranges 45 | * add `redirect_to_dumb` (and TerminalType enum) 46 | * 47 | * - 0.4.0 (2021/11/04): 2D/3D vector plots, SVG saving 48 | * 49 | * - 0.3.1 (2021/10/23): error bars 50 | * 51 | * - 0.3.0 (2021/10/23): support for Windows 52 | * 53 | * - 0.2.1 (2020/12/16): ensure that commands sent to Gnuplot are executed 54 | * immediately 55 | * 56 | * - 0.2.0 (2020/12/14): 3D plots 57 | * 58 | * - 0.1.0 (2020/11/29): first release 59 | * 60 | */ 61 | 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | 71 | #ifdef _WIN32 72 | #include 73 | #else 74 | #include 75 | #endif 76 | 77 | const unsigned GNUPLOTPP_VERSION = 0x000901; 78 | const unsigned GNUPLOTPP_MAJOR_VERSION = (GNUPLOTPP_VERSION & 0xFF0000) >> 16; 79 | const unsigned GNUPLOTPP_MINOR_VERSION = (GNUPLOTPP_VERSION & 0x00FF00) >> 8; 80 | const unsigned GNUPLOTPP_PATCH_VERSION = (GNUPLOTPP_VERSION & 0xFF); 81 | 82 | /** 83 | * High-level interface to the Gnuplot executable 84 | * 85 | * This class establishes a connection with a new Gnuplot instance and 86 | * sends commands to it through a pipe. It is able to directly plot 87 | * vectors of numbers by saving them in temporary files. 88 | */ 89 | class Gnuplot { 90 | private: 91 | static FILE *safe_popen(const char *name, const char *mode) { 92 | #ifdef _WIN32 93 | return _popen(name, mode); 94 | #else 95 | return popen(name, mode); 96 | #endif 97 | } 98 | 99 | static int safe_pclose(FILE *f) { 100 | #ifdef _WIN32 101 | return _pclose(f); 102 | #else 103 | return pclose(f); 104 | #endif 105 | } 106 | 107 | static void safe_sleep(unsigned seconds) { 108 | #ifdef _WIN32 109 | Sleep(seconds * 1000); // Sleep on Windows requires milliseconds 110 | #else 111 | sleep(seconds); 112 | #endif 113 | } 114 | 115 | std::string escape_quotes(const std::string &s) { 116 | std::string result{}; 117 | 118 | for (char c : s) { 119 | if (c != '\'') 120 | result.push_back(c); 121 | else 122 | result += "''"; 123 | } 124 | 125 | return result; 126 | } 127 | 128 | std::vector list_of_x; 129 | std::vector list_of_y; 130 | std::vector list_of_xerr; 131 | std::vector list_of_yerr; 132 | 133 | void check_consistency() const { 134 | assert(list_of_x.size() == list_of_y.size()); 135 | 136 | if(list_of_xerr.size() > 0) 137 | assert(list_of_xerr.size() == list_of_x.size()); 138 | if(list_of_yerr.size() > 0) 139 | assert(list_of_yerr.size() == list_of_y.size()); 140 | } 141 | 142 | public: 143 | enum class LineStyle { 144 | DOTS, 145 | LINES, 146 | POINTS, 147 | LINESPOINTS, 148 | STEPS, 149 | BOXES, 150 | X_ERROR_BARS, 151 | Y_ERROR_BARS, 152 | XY_ERROR_BARS, 153 | VECTORS, 154 | }; 155 | 156 | enum class AxisScale { 157 | LINEAR, 158 | LOGX, 159 | LOGY, 160 | LOGXY, 161 | }; 162 | 163 | enum class TerminalMode { 164 | MONO, 165 | ANSI, 166 | ANSI256, 167 | ANSIRGB, 168 | }; 169 | 170 | Gnuplot(const char *executable_name = "gnuplot", bool persist = true) 171 | : connection{}, series{}, files_to_delete{}, is_3dplot{false} { 172 | std::stringstream os; 173 | // The --persist flag lets Gnuplot keep running after the C++ 174 | // program has completed its execution 175 | os << executable_name; 176 | if (persist) 177 | os << " --persist"; 178 | connection = safe_popen(os.str().c_str(), "w"); 179 | 180 | set_xrange(); 181 | set_yrange(); 182 | set_zrange(); 183 | 184 | // See 185 | // https://stackoverflow.com/questions/28152719/how-to-make-gnuplot-use-the-unicode-minus-sign-for-negative-numbers 186 | sendcommand("set encoding utf8\n"); 187 | sendcommand("set minussign"); 188 | } 189 | 190 | ~Gnuplot() { 191 | // Bye bye, Gnuplot! 192 | if (connection) { 193 | safe_pclose(connection); 194 | connection = nullptr; 195 | } 196 | 197 | // Let some time pass before removing the files, so that Gnuplot 198 | // can finish displaying the last plot. 199 | safe_sleep(1); 200 | 201 | // Now remove the data files 202 | for (const auto &fname : files_to_delete) { 203 | std::remove(fname.c_str()); 204 | } 205 | } 206 | 207 | /* This is the most low-level method in the Gnuplot class! It 208 | returns `true` if the send command was successful, `false` 209 | otherwise. */ 210 | bool sendcommand(const char *str) { 211 | if (!ok()) 212 | return false; 213 | 214 | fputs(str, connection); 215 | fputc('\n', connection); 216 | fflush(connection); 217 | 218 | return true; 219 | } 220 | 221 | bool sendcommand(const std::string &str) { return sendcommand(str.c_str()); } 222 | bool sendcommand(const std::stringstream &stream) { 223 | return sendcommand(stream.str()); 224 | } 225 | 226 | bool ok() { return connection != nullptr; } 227 | 228 | /* Save the plot to a PNG file instead of displaying a window */ 229 | bool redirect_to_png(const std::string &filename, 230 | const std::string &size = "800,600") { 231 | std::stringstream os; 232 | 233 | os << "set terminal pngcairo color enhanced size " << size << "\n" 234 | << "set output '" << filename << "'\n"; 235 | return sendcommand(os); 236 | } 237 | 238 | /* Save the plot to a PDF file instead of displaying a window */ 239 | bool redirect_to_pdf(const std::string &filename, 240 | std::string size = "16cm,12cm") { 241 | std::stringstream os; 242 | 243 | os << "set terminal pdfcairo color enhanced size " << size << "\n" 244 | << "set output '" << filename << "'\n"; 245 | return sendcommand(os); 246 | } 247 | 248 | /* Save the plot to a SVG file instead of displaying a window */ 249 | bool redirect_to_svg(const std::string &filename, 250 | const std::string &size = "800,600") { 251 | std::stringstream os; 252 | 253 | os << "set terminal svg enhanced mouse standalone size " << size << "\n" 254 | << "set output '" << filename << "'\n"; 255 | return sendcommand(os); 256 | } 257 | 258 | /* Save the plot to an animated GIF. The delay between frames is specified 259 | * by the `delay_ms` parameter (in milliseconds). If `loop` is `true` (the 260 | * default), the animation will loop indefinitely, otherwise it will just 261 | * play once and stop at the last frame. 262 | * 263 | * Note that frames are saved only once you call `Gnuplot::show()`. Therefore, 264 | * if you want to put N frames in your animation, you have to call 265 | * `Gnuplot::show()` exactly N times. 266 | */ 267 | bool redirect_to_animated_gif(const std::string &filename, 268 | const std::string &size = "800,600", 269 | int delay_ms = 50, 270 | bool loop = true) { 271 | std::stringstream os; 272 | 273 | // Unfortunately, Gnuplot requires the delay to be expressed in units of 1/100 s 274 | // instead of the more common unit 1/1000 s, so we need to divide by 10. 275 | // We do not support a fixed number of repetitions: either you loop infinitely 276 | // or play the animation just once 277 | os << "set terminal gif animate delay " << delay_ms / 10 << " loop " << (loop ? 0 : 1) << "\n" 278 | << "set output '" << filename << "'\n"; 279 | return sendcommand(os); 280 | } 281 | 282 | /* Send the plot to the terminal or to a text file */ 283 | bool redirect_to_dumb(const std::string &filename = "", 284 | unsigned int width = 80, 285 | unsigned int height = 50, 286 | TerminalMode mode = TerminalMode::MONO) { 287 | std::stringstream os; 288 | 289 | os << "set terminal dumb size " << width << " " << height; 290 | 291 | switch(mode) { 292 | case TerminalMode::MONO: os << "mono"; break; 293 | case TerminalMode::ANSI: os << "ansi"; break; 294 | case TerminalMode::ANSI256: os << "ansi256"; break; 295 | case TerminalMode::ANSIRGB: os << "ansirgb"; break; 296 | default: os << "mono"; 297 | } 298 | 299 | os << "\n"; 300 | 301 | if (! filename.empty()) { 302 | os << "set output '" << filename << "'\n"; 303 | } 304 | 305 | return sendcommand(os); 306 | } 307 | 308 | bool set_title(const std::string &title) { 309 | std::stringstream os; 310 | os << "set title '" << escape_quotes(title) << "'"; 311 | return sendcommand(os); 312 | } 313 | 314 | /* Set the label on the X axis */ 315 | bool set_xlabel(const std::string &label) { 316 | std::stringstream os; 317 | os << "set xlabel '" << escape_quotes(label) << "'"; 318 | return sendcommand(os); 319 | } 320 | 321 | /* Set the label on the Y axis */ 322 | bool set_ylabel(const std::string &label) { 323 | std::stringstream os; 324 | os << "set ylabel '" << escape_quotes(label) << "'"; 325 | return sendcommand(os); 326 | } 327 | 328 | /* Set the minimum and maximum value to be displayed along the X axis */ 329 | void set_xrange(double min = NAN, double max = NAN) { 330 | xrange = format_range(min, max); 331 | } 332 | 333 | /* Set the minimum and maximum value to be displayed along the X axis */ 334 | void set_yrange(double min = NAN, double max = NAN) { 335 | yrange = format_range(min, max); 336 | } 337 | 338 | /* Set the minimum and maximum value to be displayed along the X axis */ 339 | void set_zrange(double min = NAN, double max = NAN) { 340 | zrange = format_range(min, max); 341 | } 342 | 343 | bool set_logscale(AxisScale scale) { 344 | switch (scale) { 345 | case AxisScale::LOGX: 346 | return sendcommand("set logscale x"); 347 | case AxisScale::LOGY: 348 | return sendcommand("set logscale y"); 349 | case AxisScale::LOGXY: 350 | return sendcommand("set logscale xy"); 351 | default: 352 | return sendcommand("unset logscale"); 353 | } 354 | } 355 | 356 | template 357 | void plot(const std::vector &y, const std::string &label = "", 358 | LineStyle style = LineStyle::LINES) { 359 | _plot(label, style, false, y); 360 | } 361 | 362 | template 363 | void plot(const std::vector &x, const std::vector &y, 364 | const std::string &label = "", LineStyle style = LineStyle::LINES) { 365 | _plot(label, style, false, x, y); 366 | } 367 | 368 | template 369 | void plot_xerr(const std::vector &x, const std::vector &y, 370 | const std::vector &err, const std::string &label = "") { 371 | _plot(label, LineStyle::X_ERROR_BARS, false, x, y, err); 372 | } 373 | 374 | template 375 | void plot_yerr(const std::vector &x, const std::vector &y, 376 | const std::vector &err, const std::string &label = "") { 377 | _plot(label, LineStyle::Y_ERROR_BARS, false, x, y, err); 378 | } 379 | 380 | template 381 | void plot_xyerr(const std::vector &x, const std::vector &y, 382 | const std::vector &xerr, const std::vector &yerr, 383 | const std::string &label = "") { 384 | _plot(label, LineStyle::XY_ERROR_BARS, false, x, y, xerr, yerr); 385 | } 386 | 387 | template 388 | void plot_vectors(const std::vector &x, const std::vector &y, 389 | const std::vector &vx, const std::vector &vy, 390 | const std::string &label = "") { 391 | _plot(label, LineStyle::VECTORS, false, x, y, vx, vy); 392 | } 393 | 394 | template 395 | void plot3d(const std::vector &x, const std::vector &y, 396 | const std::vector &z, const std::string &label = "", 397 | LineStyle style = LineStyle::LINES) { 398 | _plot(label, style, true, x, y, z); 399 | } 400 | 401 | template 402 | void plot_vectors3d(const std::vector &x, const std::vector &y, 403 | const std::vector &z, const std::vector &vx, 404 | const std::vector &vy, const std::vector &vz, 405 | const std::string &label = "") { 406 | _plot(label, LineStyle::VECTORS, true, x, y, z, vx, vy, vz); 407 | } 408 | 409 | /* Add a point and a X error bar to the list of samples to be plotted */ 410 | void add_point_xerr(double x, double y, double err) { 411 | check_consistency(); 412 | 413 | list_of_x.push_back(x); 414 | list_of_y.push_back(y); 415 | list_of_xerr.push_back(err); 416 | } 417 | 418 | /* Add a point and a Y error bar to the list of samples to be plotted */ 419 | void add_point_yerr(double x, double y, double err) { 420 | check_consistency(); 421 | 422 | list_of_x.push_back(x); 423 | list_of_y.push_back(y); 424 | list_of_yerr.push_back(err); 425 | } 426 | 427 | /* Add a point and two X/Y error bars to the list of samples to be plotted */ 428 | void add_point_xyerr(double x, double y, double xerr, double yerr) { 429 | check_consistency(); 430 | 431 | list_of_x.push_back(x); 432 | list_of_y.push_back(y); 433 | list_of_xerr.push_back(xerr); 434 | list_of_yerr.push_back(yerr); 435 | } 436 | /* Add a point to the list of samples to be plotted */ 437 | void add_point(double x, double y) { 438 | check_consistency(); 439 | 440 | list_of_x.push_back(x); 441 | list_of_y.push_back(y); 442 | } 443 | 444 | /* Add a value to the list of samples to be plotted */ 445 | void add_point(double y) { 446 | add_point(static_cast(list_of_x.size()), y); 447 | } 448 | 449 | /* Return the number of points added by `add_point` */ 450 | int get_num_of_points() const { 451 | check_consistency(); 452 | 453 | return (int) list_of_x.size(); 454 | } 455 | 456 | /* Return the list of abscissas for the points added by `add_point` */ 457 | const std::vector & get_points_x() const { return list_of_x; } 458 | 459 | /* Return the list of ordinates for the points added by `add_point` */ 460 | const std::vector & get_points_y() const { return list_of_y; } 461 | 462 | /* Create a plot using the values set with the method `add_point` */ 463 | void plot(const std::string &label = "", LineStyle style = LineStyle::LINES) { 464 | check_consistency(); 465 | 466 | _plot(label, style, false, list_of_x, list_of_y); 467 | } 468 | 469 | /* Create a plot with X error bars using the values set with the method `add_point` */ 470 | void plot_xerr(const std::string &label = "") { 471 | check_consistency(); 472 | 473 | plot_xerr(list_of_x, list_of_y, list_of_xerr, label); 474 | } 475 | 476 | /* Create a plot with X error bars using the values set with the method `add_point` */ 477 | void plot_yerr(const std::string &label = "") { 478 | check_consistency(); 479 | 480 | plot_yerr(list_of_x, list_of_y, list_of_yerr, label); 481 | } 482 | 483 | /* Create a plot with X error bars using the values set with the method `add_point` */ 484 | void plot_xyerr(const std::string &label = "") { 485 | check_consistency(); 486 | 487 | plot_xyerr(list_of_x, list_of_y, list_of_xerr, list_of_yerr, label); 488 | } 489 | 490 | template 491 | void histogram(const std::vector &values, size_t nbins, 492 | const std::string &label = "", 493 | LineStyle style = LineStyle::BOXES) { 494 | assert(nbins > 0); 495 | 496 | if (values.empty()) 497 | return; 498 | 499 | if (!series.empty()) { 500 | assert(!is_3dplot); 501 | } 502 | 503 | auto min_iter = std::min_element(values.begin(), values.end()); 504 | auto max_iter = std::max_element(values.begin(), values.end()); 505 | double min, max, binwidth; 506 | 507 | std::vector bins{}; 508 | 509 | // Check if all the elements are the same 510 | if (min_iter != max_iter) { 511 | min = *min_iter; 512 | max = *max_iter; 513 | binwidth = (max - min) / nbins; 514 | 515 | bins.resize(nbins); 516 | for (const auto &val : values) { 517 | int index = static_cast((val - min) / binwidth); 518 | if (index >= int(nbins)) 519 | --index; 520 | 521 | bins.at(index)++; 522 | } 523 | } else { 524 | // Just one bin… 525 | 526 | min = max = *min_iter; 527 | binwidth = 1.0; 528 | nbins = 1; 529 | bins.push_back(static_cast(values.size())); 530 | } 531 | 532 | std::stringstream of; 533 | for (size_t i{}; i < nbins; ++i) { 534 | of << min + binwidth * (i + 0.5) << " " << bins[i] << "\n"; 535 | } 536 | 537 | series.push_back(GnuplotSeries{of.str(), style, label, "1:2"}); 538 | is_3dplot = false; 539 | } 540 | 541 | // Ask Gnuplot to use a multiple-plot layout 542 | bool multiplot(int nrows, int ncols, const std::string &title = "") { 543 | std::stringstream os; 544 | os << "set multiplot layout " << nrows << ", " << ncols << " title '" 545 | << escape_quotes(title) << "'\n"; 546 | return sendcommand(os); 547 | } 548 | 549 | // Force Gnuplot to draw all the series sent through any of the `plot` 550 | // commands 551 | bool show(bool call_reset = true) { 552 | if (series.empty()) 553 | return true; 554 | 555 | std::stringstream os; 556 | os << "set style fill solid 0.5\n"; 557 | 558 | // Write the data in separate series 559 | for (size_t i{}; i < series.size(); ++i) { 560 | const GnuplotSeries &s = series.at(i); 561 | os << "$Datablock" << i << " << EOD\n" << s.data_string << "\nEOD\n"; 562 | } 563 | 564 | if (is_3dplot) { 565 | os << "splot " << xrange << " " << yrange << " " << zrange << " "; 566 | } else { 567 | os << "plot " << xrange << " " << yrange << " "; 568 | } 569 | 570 | // Plot the series we have just defined 571 | for (size_t i{}; i < series.size(); ++i) { 572 | const GnuplotSeries &s = series.at(i); 573 | os << "$Datablock" << i << " using " << s.column_range << " with " 574 | << style_to_str(s.line_style) << " title '" << escape_quotes(s.title) 575 | << "'"; 576 | 577 | if (i + 1 < series.size()) 578 | os << ", "; 579 | } 580 | 581 | bool result = sendcommand(os); 582 | if (result && call_reset) 583 | reset(); 584 | 585 | return result; 586 | } 587 | 588 | // Remove all the series from memory and start with a blank plot 589 | void reset() { 590 | series.clear(); 591 | set_xrange(); 592 | set_yrange(); 593 | is_3dplot = false; 594 | } 595 | 596 | private: 597 | void _print_ith_elements(std::ostream &, std::ostream &, int, size_t) {} 598 | 599 | template 600 | void _print_ith_elements(std::ostream &os, std::ostream &fmts, int index, 601 | size_t i, const std::vector &v, Args... args) { 602 | os << v[i] << " "; 603 | 604 | if (i == 0) { 605 | if (index > 1) 606 | fmts << ':'; 607 | fmts << index; 608 | } 609 | 610 | _print_ith_elements(os, fmts, index + 1, i, args...); 611 | } 612 | 613 | template 614 | void _plot(const std::string &label, LineStyle style, bool is_this_3dplot, 615 | const std::vector &v, Args... args) { 616 | if (v.empty()) 617 | return; 618 | 619 | if (!series.empty()) { 620 | // Check that we are not adding a 3D plot to a 2D plot, or vice versa 621 | assert(is_3dplot == is_this_3dplot); 622 | } 623 | 624 | std::stringstream of; 625 | std::stringstream fmtstring; 626 | for (size_t i{}; i < v.size(); ++i) { 627 | _print_ith_elements(of, fmtstring, 1, i, v, args...); 628 | of << "\n"; 629 | } 630 | 631 | series.push_back(GnuplotSeries{of.str(), style, label, fmtstring.str()}); 632 | is_3dplot = is_this_3dplot; 633 | } 634 | 635 | struct GnuplotSeries { 636 | std::string data_string; 637 | LineStyle line_style; 638 | std::string title; 639 | std::string column_range; 640 | }; 641 | 642 | std::string style_to_str(LineStyle style) { 643 | switch (style) { 644 | case LineStyle::DOTS: 645 | return "dots"; 646 | case LineStyle::POINTS: 647 | return "points"; 648 | case LineStyle::LINESPOINTS: 649 | return "linespoints"; 650 | case LineStyle::STEPS: 651 | return "steps"; 652 | case LineStyle::BOXES: 653 | return "boxes"; 654 | case LineStyle::X_ERROR_BARS: 655 | return "xerrorbars"; 656 | case LineStyle::Y_ERROR_BARS: 657 | return "yerrorbars"; 658 | case LineStyle::XY_ERROR_BARS: 659 | return "xyerrorbars"; 660 | case LineStyle::VECTORS: 661 | return "vectors"; 662 | default: 663 | return "lines"; 664 | } 665 | } 666 | 667 | std::string format_range(double min = NAN, double max = NAN) { 668 | if (std::isnan(min) && std::isnan(max)) 669 | return "[]"; 670 | 671 | std::stringstream os; 672 | os << "["; 673 | 674 | if (std::isnan(min)) 675 | os << "*"; 676 | else 677 | os << min; 678 | 679 | os << ":"; 680 | if (std::isnan(max)) 681 | os << "*"; 682 | else 683 | os << max; 684 | 685 | os << "]"; 686 | 687 | return os.str(); 688 | } 689 | 690 | FILE *connection; 691 | std::vector series; 692 | std::vector files_to_delete; 693 | std::string xrange; 694 | std::string yrange; 695 | std::string zrange; 696 | bool is_3dplot; 697 | }; 698 | -------------------------------------------------------------------------------- /images/3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/3d.png -------------------------------------------------------------------------------- /images/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/animation.gif -------------------------------------------------------------------------------- /images/complex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/complex.png -------------------------------------------------------------------------------- /images/dumb-terminal-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/dumb-terminal-example.png -------------------------------------------------------------------------------- /images/errorbars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/errorbars.png -------------------------------------------------------------------------------- /images/example-vec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/example-vec.png -------------------------------------------------------------------------------- /images/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/histogram.png -------------------------------------------------------------------------------- /images/multipleseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/multipleseries.png -------------------------------------------------------------------------------- /images/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ziotom78/gplotpp/970f2bf4762534c880fed31156b7b6dc3f306995/images/output.png -------------------------------------------------------------------------------- /tests/run_tests.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include "doctest.h" 3 | 4 | DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END 13 | 14 | #include "../gplot++.h" 15 | 16 | using namespace std; 17 | 18 | string read_file(const string & file_name) { 19 | INFO("Reading text file ", file_name); 20 | 21 | FILE *fin{fopen(file_name.c_str(), "rt")}; 22 | CHECK(fin != nullptr); 23 | 24 | string result; 25 | 26 | while (true) { 27 | int next_char = fgetc(fin); 28 | if (next_char == EOF) break; 29 | 30 | char c{static_cast(next_char)}; 31 | if (c != '\n' && c != '\r' && c != '\f') result += c; 32 | } 33 | 34 | return result; 35 | } 36 | 37 | // This is useful to make the program wait until Gnuplot finishes 38 | // writing stuff on the "dumb" terminal 39 | void wait() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } 40 | 41 | TEST_CASE("complex") { 42 | const string file_name{"complex.svg"}; 43 | 44 | { 45 | Gnuplot plt{}; 46 | 47 | plt.redirect_to_svg(file_name); 48 | 49 | vector x{1, 2, 3, 4, 5}; 50 | vector y{5, 4, 3, 2, 1}; 51 | 52 | plt.plot(x, y, "Series #1", Gnuplot::LineStyle::POINTS); 53 | plt.plot(x, x, "Series #2", Gnuplot::LineStyle::POINTS); 54 | plt.set_xlabel("X axis"); 55 | plt.set_ylabel("Y axis"); 56 | plt.show(); 57 | } // Call Gnuplot::~Gnuplot() for plt and save the file 58 | 59 | wait(); 60 | 61 | string file_contents{read_file(file_name)}; 62 | 63 | CHECK(file_contents.find("Series #1") != string::npos); 64 | CHECK(file_contents.find("Series #2") != string::npos); 65 | CHECK(file_contents.find("X axis") != string::npos); 66 | CHECK(file_contents.find("Y axis") != string::npos); 67 | } 68 | 69 | TEST_CASE("animation") { 70 | const string file_name{"animation.gif"}; 71 | 72 | { 73 | Gnuplot plt{}; 74 | 75 | plt.redirect_to_animated_gif(file_name); 76 | 77 | vector x{1, 2, 3, 4, 5}; 78 | vector y{5, 4, 3, 2, 1}; 79 | 80 | for(int i{}; i < (int) x.size(); ++i) { 81 | plt.add_point(x[i], y[i]); 82 | 83 | // Draw the frame 84 | plt.plot(); 85 | 86 | // Add it to the GIF file 87 | plt.show(); 88 | } 89 | } 90 | 91 | wait(); 92 | 93 | // No checks, just try to compile the code above and verify that no 94 | // errors are issued 95 | } 96 | --------------------------------------------------------------------------------