Skip to content

Commit 6d21603

Browse files
committed
Add redirect_to_animated_gif, bump to version 0.9.0
1 parent 9a676f2 commit 6d21603

File tree

5 files changed

+150
-1
lines changed

5 files changed

+150
-1
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ add_executable(example-addpoint
2323
example-addpoint.cpp
2424
)
2525

26+
add_executable(example-animated-gif
27+
example-animated-gif.cpp
28+
)
29+
2630
add_executable(example-complex
2731
example-complex.cpp
2832
)

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ A few features of this library are the following:
4242
* [3D plots](#3d-plots)
4343
* [Vector fields](#vector-fields)
4444
* [Saving plots to a file](#saving-plots-to-a-file)
45+
* [Animations](#animations)
4546
* [Low-level interface](#low-level-interface)
4647
* [Similar libraries](#similar-libraries)
4748
* [Changelog](#changelog)
@@ -482,6 +483,43 @@ Finally, you can use `Gnuplot::redirect_to_dumb` to send the plot to the termina
482483

483484
![](images/dumb-terminal-example.png)
484485

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<double> 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+
485523
### Low-level interface
486524
487525
You can pass commands to Gnuplot using the method `Gnuplot::sendcommand`:

example-animated-gif.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 <cstdio>
26+
#include <iostream>
27+
28+
int main(void) {
29+
Gnuplot gnuplot{};
30+
std::vector<double> 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+
}

gplot++.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
*
2929
* Version history
3030
*
31+
* - 0.9.0 (2024/11/19): new method `redirect_to_animated_gif`
32+
*
3133
* - 0.8.0 (2024/10/15): new methods `add_point_xerr`,
3234
* `add_point_yerr`, and `add_point_xyerr`,
3335
* and new overloads for functions
@@ -70,7 +72,7 @@
7072
#include <unistd.h>
7173
#endif
7274

73-
const unsigned GNUPLOTPP_VERSION = 0x000800;
75+
const unsigned GNUPLOTPP_VERSION = 0x000900;
7476
const unsigned GNUPLOTPP_MAJOR_VERSION = (GNUPLOTPP_VERSION & 0xFF0000) >> 16;
7577
const unsigned GNUPLOTPP_MINOR_VERSION = (GNUPLOTPP_VERSION & 0x00FF00) >> 8;
7678
const unsigned GNUPLOTPP_PATCH_VERSION = (GNUPLOTPP_VERSION & 0xFF);
@@ -251,6 +253,30 @@ class Gnuplot {
251253
return sendcommand(os);
252254
}
253255

256+
/* Save the plot to an animated GIF. The delay between frames is specified
257+
* by the `delay_ms` parameter (in milliseconds). If `loop` is `true` (the
258+
* default), the animation will loop indefinitely, otherwise it will just
259+
* play once and stop at the last frame.
260+
*
261+
* Note that frames are saved only once you call `Gnuplot::show()`. Therefore,
262+
* if you want to put N frames in your animation, you have to call
263+
* `Gnuplot::show()` exactly N times.
264+
*/
265+
bool redirect_to_animated_gif(const std::string &filename,
266+
const std::string &size = "800,600",
267+
int delay_ms = 50,
268+
bool loop = true) {
269+
std::stringstream os;
270+
271+
// Unfortunately, Gnuplot requires the delay to be expressed in units of 1/100 s
272+
// instead of the more common unit 1/1000 s, so we need to divide by 10.
273+
// We do not support a fixed number of repetitions: either you loop infinitely
274+
// or play the animation just once
275+
os << "set terminal gif animate delay " << delay_ms / 10 << " loop " << (loop ? 0 : 1) << "\n"
276+
<< "set output '" << filename << "'\n";
277+
return sendcommand(os);
278+
}
279+
254280
/* Send the plot to the terminal or to a text file */
255281
bool redirect_to_dumb(const std::string &filename = "",
256282
unsigned int width = 80,

tests/run_tests.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,31 @@ TEST_CASE("complex") {
6565
CHECK(file_contents.find("X axis") != string::npos);
6666
CHECK(file_contents.find("Y axis") != string::npos);
6767
}
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<double> x{1, 2, 3, 4, 5};
78+
vector<double> 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+
}

0 commit comments

Comments
 (0)