Skip to content

Commit 07a73fa

Browse files
oKermorgantBenno Evers
authored andcommitted
Add dynamic plot class
1 parent 8babc98 commit 07a73fa

File tree

3 files changed

+220
-3
lines changed

3 files changed

+220
-3
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill
1+
examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update
22

33
minimal: examples/minimal.cpp matplotlibcpp.h
44
cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python2.7 -lpython2.7 -o minimal -std=c++11
@@ -32,6 +32,9 @@ fill_inbetween: examples/fill_inbetween.cpp matplotlibcpp.h
3232

3333
fill: examples/fill.cpp matplotlibcpp.h
3434
cd examples && g++ fill.cpp -I/usr/include/python2.7 -lpython2.7 -o fill -std=c++11
35+
36+
update: examples/update.cpp matplotlibcpp.h
37+
cd examples && g++ update.cpp -I/usr/include/python2.7 -lpython2.7 -o update -std=c++11
3538

3639
clean:
37-
rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill}
40+
rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill,update}

examples/update.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#define _USE_MATH_DEFINES
2+
#include <cmath>
3+
#include "../matplotlibcpp.h"
4+
#include <chrono>
5+
6+
namespace plt = matplotlibcpp;
7+
8+
void update_window(const double x, const double y, const double t,
9+
std::vector<double> &xt, std::vector<double> &yt)
10+
{
11+
const double target_length = 300;
12+
const double half_win = (target_length/(2.*sqrt(1.+t*t)));
13+
14+
xt[0] = x - half_win;
15+
xt[1] = x + half_win;
16+
yt[0] = y - half_win*t;
17+
yt[1] = y + half_win*t;
18+
}
19+
20+
21+
int main()
22+
{
23+
24+
bool use_dynamic_plot = false;
25+
bool timeit = true;
26+
27+
size_t n = 1000;
28+
std::vector<double> x, y;
29+
30+
const double w = 0.05;
31+
const double a = n/2;
32+
33+
for(size_t i=0; i<n; i++) {
34+
x.push_back(i);
35+
y.push_back(a*sin(w*i));
36+
}
37+
38+
std::vector<double> xt(2), yt(2);
39+
40+
plt::title("Sample figure");
41+
42+
std::chrono::time_point<std::chrono::system_clock> start, end;
43+
start = std::chrono::system_clock::now();
44+
45+
if(use_dynamic_plot)
46+
{
47+
plt::xlim(x.front(), x.back());
48+
plt::ylim(-a,a);
49+
plt::axis("equal");
50+
51+
// plot sin once and for all
52+
plt::named_plot("sin", x, y);
53+
54+
// prepare plotting the tangent
55+
plt::Plot plot("tangent");
56+
57+
plt::legend();
58+
59+
for(size_t i=0; i<n; i++) {
60+
61+
if (i % 10 == 0) {
62+
{
63+
update_window(x[i], y[i], a*w*cos(w*x[i]), xt, yt);
64+
// just update data for this plot
65+
plot.update(xt, yt);
66+
}
67+
68+
// Display plot continuously
69+
if(!timeit)
70+
plt::pause(0.1);
71+
}
72+
}
73+
}
74+
75+
else
76+
{
77+
for(size_t i=0; i<n; i++) {
78+
79+
if (i % 10 == 0) {
80+
{
81+
plt::clf();
82+
83+
plt::named_plot("sin", x, y);
84+
85+
update_window(x[i], y[i], a*w*cos(w*i), xt, yt);
86+
plt::named_plot("tangent", xt, yt);
87+
88+
// we have to control axis size
89+
plt::xlim(x.front(), x.back());
90+
plt::ylim(-a,a);
91+
plt::axis("equal");
92+
plt::legend();
93+
94+
}
95+
96+
// Display plot continuously
97+
if(!timeit)
98+
plt::pause(0.1);
99+
}
100+
}
101+
}
102+
103+
end = std::chrono::system_clock::now();
104+
double elapsed_seconds = std::chrono::duration_cast<std::chrono::microseconds>
105+
(end-start).count();
106+
if(use_dynamic_plot)
107+
std::cout << "dynamic";
108+
else
109+
std::cout << "static";
110+
111+
std::cout << " : " << elapsed_seconds/1000 << " ms\n";
112+
}

matplotlibcpp.h

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ inline void show(const bool block = true)
14391439
PyObject *kwargs = PyDict_New();
14401440
PyDict_SetItemString(kwargs, "block", Py_False);
14411441
res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs);
1442-
Py_DECREF(kwargs);
1442+
Py_DECREF(kwargs);
14431443
}
14441444

14451445

@@ -1706,4 +1706,106 @@ inline bool plot(const std::vector<double>& x, const std::vector<double>& y, con
17061706
return plot<double>(x,y,keywords);
17071707
}
17081708

1709+
/*
1710+
* This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting
1711+
*/
1712+
1713+
class Plot
1714+
{
1715+
public:
1716+
// default initialization with plot label, some data and format
1717+
template<typename Numeric>
1718+
Plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
1719+
1720+
assert(x.size() == y.size());
1721+
1722+
PyObject* kwargs = PyDict_New();
1723+
if(name != "")
1724+
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1725+
1726+
PyObject* xarray = get_array(x);
1727+
PyObject* yarray = get_array(y);
1728+
1729+
PyObject* pystring = PyString_FromString(format.c_str());
1730+
1731+
PyObject* plot_args = PyTuple_New(3);
1732+
PyTuple_SetItem(plot_args, 0, xarray);
1733+
PyTuple_SetItem(plot_args, 1, yarray);
1734+
PyTuple_SetItem(plot_args, 2, pystring);
1735+
1736+
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
1737+
1738+
Py_DECREF(kwargs);
1739+
Py_DECREF(plot_args);
1740+
1741+
if(res)
1742+
{
1743+
line= PyList_GetItem(res, 0);
1744+
1745+
if(line)
1746+
set_data_fct = PyObject_GetAttrString(line,"set_data");
1747+
else
1748+
Py_DECREF(line);
1749+
Py_DECREF(res);
1750+
}
1751+
}
1752+
1753+
// shorter initialization with name or format only
1754+
// basically calls line, = plot([], [])
1755+
Plot(const std::string& name = "", const std::string& format = "")
1756+
: Plot(name, std::vector<double>(), std::vector<double>(), format) {}
1757+
1758+
template<typename Numeric>
1759+
bool update(const std::vector<Numeric>& x, const std::vector<Numeric>& y) {
1760+
assert(x.size() == y.size());
1761+
if(set_data_fct)
1762+
{
1763+
PyObject* xarray = get_array(x);
1764+
PyObject* yarray = get_array(y);
1765+
1766+
PyObject* plot_args = PyTuple_New(2);
1767+
PyTuple_SetItem(plot_args, 0, xarray);
1768+
PyTuple_SetItem(plot_args, 1, yarray);
1769+
1770+
PyObject* res = PyObject_CallObject(set_data_fct, plot_args);
1771+
if (res) Py_DECREF(res);
1772+
return res;
1773+
}
1774+
return false;
1775+
}
1776+
1777+
// clears the plot but keep it available
1778+
bool clear() {
1779+
return update(std::vector<double>(), std::vector<double>());
1780+
}
1781+
1782+
// definitely remove this line
1783+
void remove() {
1784+
if(line)
1785+
{
1786+
auto remove_fct = PyObject_GetAttrString(line,"remove");
1787+
PyObject* args = PyTuple_New(0);
1788+
PyObject* res = PyObject_CallObject(remove_fct, args);
1789+
if (res) Py_DECREF(res);
1790+
}
1791+
decref();
1792+
}
1793+
1794+
~Plot() {
1795+
decref();
1796+
}
1797+
private:
1798+
1799+
void decref() {
1800+
if(line)
1801+
Py_DECREF(line);
1802+
if(set_data_fct)
1803+
Py_DECREF(set_data_fct);
1804+
}
1805+
1806+
1807+
PyObject* line = nullptr;
1808+
PyObject* set_data_fct = nullptr;
1809+
};
1810+
17091811
} // end namespace matplotlibcpp

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy