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)
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