10000 Iniital commit · xuzhenqi/matplotlib-cpp@3f25969 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3f25969

Browse files
author
Benno Evers
committed
Iniital commit
1 parent 2d7d532 commit 3f25969

File tree

8 files changed

+394
-0
lines changed

8 files changed

+394
-0
lines changed

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
examples: minimal basic modern
2+
3+
minimal: examples/minimal.cpp matplotlibcpp.h
4+
cd examples && g++ minimal.cpp -lpython2.7 -o minimal -std=c++11
5+
6+
basic: examples/basic.cpp matplotlibcpp.h
7+
cd examples && g++ basic.cpp -lpython2.7 -o basic
8+
9+
modern: examples/modern.cpp matplotlibcpp.h
10+
cd examples && g++ modern.cpp -lpython2.7 -o modern -std=c++11
11+

README

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
matplotlib-cpp
2+
==============
3+
4+
This is matplotlib-cpp, probably the simplest C++ plotting library.
5+
It is built to resemble the plotting API used by Matlab and matplotlib.
6+
7+
Usage
8+
-----
9+
Complete minimal example:
10+
11+
#include "matplotlibcpp.h"
12+
namespace plt = matplotlibcpp;
13+
int main() {
14+
std::vector<double> v {1,2,3,4};
15+
plt::plot(v);
16+
plt::show();
17+
}
18+
19+
// g++ minimal.cpp -std=c++11 -lpython2.7
20+
21+
Result: ![Minimal example](./examples/minimal.png)
22+
23+
A more comprehensive example:
24+
25+
#include "matplotlibcpp.h"
26+
#include <cmath>
27+
28+
namespace plt = matplotlibcpp;
29+
30+
int main()
31+
{
32+
// Prepare data.
33+
int n = 5000;
34+
std::vector<double> x(n), y(n), z(n), w(n,2);
35+
for(int i=0; i<n; ++i) {
36+
x.at(i) = i*i;
37+
y.at(i) = sin(2*M_PI*i/360.0);
38+
z.at(i) = log(i);
39+
}
40+
41+
// Plot line from given x and y data. Color is selected automatically.
42+
plt::plot(x, y);
43+
// Plot a red dashed line from given x and y data.
44+
plt::plot(x, w,"r--");
45+
// Plot a line whose name will show up as "log(x)" in the legend.
46+
plt::named_plot("log(x)", x, z);
47+
48+
// Set x-axis to interval [0,1000000]
49+
plt::xlim(0, 1000*1000);
50+
// Enable legend.
51+
plt::legend();
52+
// Show plot
53+
plt::show();
54+
}
55+
56+
Result: ![Basic example](./examples/basic.png)
57+
58+
Installation
59+
------------
60+
matplotlib-cpp works by wrapping the popular python plotting library matplotlib. (matplotlib.org)
61+
This means you have to have a working python installation, including development headers.
62+
On Ubuntu:
63+
64+
sudo aptitude install python-matplotlib python2.7-dev
65+
66+
The C++-part of the library consists of the single header file matplotlibcpp.h which can be placed
67+
anywhere.
68+
Since a python interpreter is opened internally, it is necessary to link against libpython2.7 in order to use
69+
matplotlib-cpp.
70+
(There should be no problems using python3 instead of python2.7, if desired)
71+
72+
73+
Todo/Issues/Wishlist
74+
--------------------
75+
* It would be nice to have a more object-oriented design with a Plot class which would allow
76+
multiple independent plots per program.
77+
78+
* Right now, only a small subset of matplotlibs functionality is exposed. Stuff like xlabel()/ylabel() etc. should
79+
be easy to add.

examples/basic.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "../matplotlibcpp.h"
2+
3+
#include <cmath>
4+
5+
namespace plt = matplotlibcpp;
6+
7+
int main()
8+
{
9+
// Prepare data.
10+
int n = 5000;
11+
std::vector<double> x(n), y(n), z(n), w(n,2);
12+
for(int i=0; i<n; ++i) {
13+
x.at(i) = i*i;
14+
y.at(i) = sin(2*M_PI*i/360.0);
15+
z.at(i) = log(i);
16+
}
17+
18+
// Plot line from given x and y data. Color is selected automatically.
19+
plt::plot(x, y);
20+
// Plot a red dashed line from given x and y data.
21+
plt::plot(x, w,"r--");
22+
// Plot a line whose name will show up as "log(x)" in the legend.
23+
plt::named_plot("log(x)", x, z);
24+
25+
// Set x-axis to interval [0,1000000]
26+
plt::xlim(0, 1000*1000);
27+
// Enable legend.
28+
plt::legend();
29+
// Show plot
30+
plt::show();
31+
}

examples/basic.png

23.3 KB
Loading

examples/minimal.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "../matplotlibcpp.h"
2+
3+
namespace plt = matplotlibcpp;
4+
5+
int main() {
6+
std::vector<double> v {1,2,3,4};
7+
plt::plot(v);
8+
plt::show();
9+
}

examples/minimal.png

18.2 KB
Loading

examples/modern.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include "../matplotlibcpp.h"
2+
3+
namespace plt = matplotlibcpp;
4+
5+
int main()
6+
{
7+
// plot(y) - the x-coordinates are implicitly set to [0,1,...,n)
8+
plt::plot({1,2,3,1,3.5,2.5});
9+
// plot(x,y,format) - plot as solid red line with circular markers
10+
plt::plot({5,4,3,2,-1}, {-1, 4, 2, 7, 1}, "ro-");
11+
12+
// show plots
13+
plt::show();
14+
}

matplotlibcpp.h

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <map>
5+
#include <numeric>
6+
#include <stdexcept>
7+
8+
#include <python2.7/Python.h>
9+
10+
namespace matplotlibcpp {
11+
12+
namespace detail {
13+
struct _pyplot_global {
14+
PyObject *s_python_function_show;
15+
PyObject *s_python_function_figure;
16+
PyObject *s_python_function_plot;
17+
PyObject *s_python_function_legend;
18+
PyObject *s_python_function_xlim;
19+
PyObject *s_python_function_ylim;
20+
PyObject *s_python_empty_tuple;
21+
22+
static _pyplot_global& get() {
23+
static _pyplot_global ctx;
24+
return ctx;
25+
}
26+
27+
private:
28+
_pyplot_global() {
29+
Py_SetProgramName("plotting"); /* optional but recommended */
30+
Py_Initialize();
31+
32+
PyObject* pyname = PyString_FromString("matplotlib.pyplot");
33+
if(!pyname) { throw std::runtime_error("couldnt create string"); }
34+
35+
PyObject* pymod = PyImport_Import(pyname);
36+
Py_DECREF(pyname);
37+
if(!pymod) { throw std::runtime_error("Error loading module!"); }
38+
39+
s_python_function_show = PyObject_GetAttrString(pymod, "show");
40+
s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
41+
s_python_function_plot = PyObject_GetAttrString(pymod, "plot");
42+
s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
43+
s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim");
44+
s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim");
45+
46+
if(!s_python_function_show
47+
|| !s_python_function_figure
48+
|| !s_python_function_plot
49+
|| !s_python_function_legend
50+
|| !s_python_function_xlim
51+
|| !s_python_function_ylim)
52+
{ throw std::runtime_error("Couldnt find required function!"); }
53+
54+
if(!PyFunction_Check(s_python_function_show)
55+
|| !PyFunction_Check(s_python_function_figure)
56+
|| !PyFunction_Check(s_python_function_plot)
57+
|| !PyFunction_Check(s_python_function_legend)
58+
|| !PyFunction_Check(s_python_function_xlim)
59+
|| !PyFunction_Check(s_python_function_ylim))
60+
{ throw std::runtime_error("Python object is unexpectedly not a PyFunction."); }
61+
62+
s_python_empty_tuple = PyTuple_New(0);
63+
}
64+
65+
~_pyplot_global() {
66+
Py_Finalize();
67+
}
68+
};
69+
}
70+
71+
72+
73+
template<typename Numeric>
74+
bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
75+
{
76+
assert(x.size() == y.size());
77+
78+
// using python lists
79+
PyObject* xlist = PyList_New(x.size());
80+
PyObject* ylist = PyList_New(y.size());
81+
82+
for(size_t i = 0; i < x.size(); ++i) {
83+
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
84+
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
85+
}
86+
87+
// construct positional args
88+
PyObject* args = PyTuple_New(2);
89+
PyTuple_SetItem(args, 0, xlist);
90+
PyTuple_SetItem(args, 1, ylist);
91+
92+
Py_DECREF(xlist);
93+
Py_DECREF(ylist);
94+
95+
// construct keyword args
96+
PyObject* kwargs = PyDict_New();
97+
for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
98+
{
99+
PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
100+
}
101+
102+
PyObject* res = PyObject_Call(detail::_pyplot_global::get().s_python_function_plot, args, kwargs);
103+
104+
Py_DECREF(args);
105+
Py_DECREF(kwargs);
106+
if(res) Py_DECREF(res);
107+
108+
return res;
109+
}
110+
111+
112+
template<typename Numeric>
113+
bool plot(const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
114+
assert(x.size() == y.size());
115+
116+
PyObject* xlist = PyList_New(x.size());
117+
PyObject* ylist = PyList_New(y.size());
118+
PyObject* pystring = PyString_FromString(format.c_str());
119+
120+
for(size_t i = 0; i < x.size(); ++i) {
121+
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
122+
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
123+
}
124+
125+
PyObject* plot_args = PyTuple_New(3);
126+
PyTuple_SetItem(plot_args, 0, xlist);
127+
PyTuple_SetItem(plot_args, 1, ylist);
128+
PyTuple_SetItem(plot_args, 2, pystring);
129+
130+
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_plot, plot_args);
131+
132+
Py_DECREF(xlist);
133+
Py_DECREF(ylist);
134+
Py_DECREF(plot_args);
135+
if(res) Py_DECREF(res);
136+
137+
return res;
138+
}
139+
140+
141+
template<typename Numeric>
142+
bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
143+
PyObject* kwargs = PyDict_New();
144+
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
145+
146+
PyObject* xlist = PyList_New(x.size());
147+
PyObject* ylist = PyList_New(y.size());
148+
PyObject* pystring = PyString_FromString(format.c_str());
149+
150+
for(size_t i = 0; i < x.size(); ++i) {
151+
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
152+
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
153+
}
154+
155+
PyObject* plot_args = PyTuple_New(3);
156+
PyTuple_SetItem(plot_args, 0, xlist);
157+
PyTuple_SetItem(plot_args, 1, ylist);
158+
PyTuple_SetItem(plot_args, 2, pystring);
159+
160+
PyObject* res = PyObject_Call(detail::_pyplot_global::get().s_python_function_plot, plot_args, kwargs);
161+
162+
Py_DECREF(kwargs);
163+
Py_DECREF(xlist);
164+
Py_DECREF(ylist);
165+
Py_DECREF(plot_args);
166+
if(res) Py_DECREF(res);
167+
168+
return res;
169+
}
170+
171+
template<typename Numeric>
172+
bool plot(const std::vector<Numeric>& y, const std::string& format = "")
173+
{
174+
std::vector<Numeric> x(y.size());
175+
for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
176+
return plot(x,y,format);
177+
}
178+
179+
/*
180+
* This group of plot() functions is needed to support initializer lists, i.e. calling
181+
* plot( {1,2,3,4} )
182+
*/
183+
bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
184+
return plot<double>(x,y,format);
185+
}
186+
187+
bool plot(const std::vector<double>& y, const std::string& format = "") {
188+
return plot<double>(y,format);
189+
}
190+
191+
bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
192+
return plot<double>(x,y,keywords);
193+
}
194+
195+
bool named_plot(const std::string& name, const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
196+
return named_plot<double>(name,x,y,format);
197+
}
198+
199+
inline void legend() {
200+
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_legend, detail::_pyplot_global::get().s_python_empty_tuple);
201+
if(!res) throw std::runtime_error("Call to legend() failed.");
202+
203+
Py_DECREF(res);
204+
}
205+
206+
template<typename Numeric>
207+
void ylim(Numeric left, Numeric right)
208+
{
209+
PyObject* list = PyList_New(2);
210+
PyList_SetItem(list, 0, PyFloat_FromDouble(left));
211+
PyList_SetItem(list, 1, PyFloat_FromDouble(right));
212+
213+
PyObject* args = PyTuple_New(1);
214+
PyTuple_SetItem(args, 0, list);
215+
216+
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_ylim, args);
217+
if(!res) throw std::runtime_error("Call to ylim() failed.");
218+
219+
Py_DECREF(list);
220+
Py_DECREF(args);
221+
Py_DECREF(res);
222+
}
223+
224+
template<typename Numeric>
225+
void xlim(Numeric left, Numeric right)
226+
{
227+
PyObject* list = PyList_New(2);
228+
PyList_SetItem(list, 0, PyFloat_FromDouble(left));
229+
PyList_SetItem(list, 1, PyFloat_FromDouble(right));
230+
231+
PyObject* args = PyTuple_New(1);
232+
PyTuple_SetItem(args, 0, list);
233+
234+
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_xlim, args);
235+
if(!res) throw std::runtime_error("Call to xlim() failed.");
236+
237+
Py_DECREF(list);
238+
Py_DECREF(args);
239+
Py_DECREF(res);
240+
}
241+
242+
inline void show() {
243+
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_show, detail::_pyplot_global::get().s_python_empty_tuple);
244+
if(!res) throw std::runtime_error("Call to show() failed.");
245+
246+
Py_DECREF(res);
247+
}
248+
249+
250+
}

0 commit comments

Comments
 (0)
0