Browse Source

Update documentation after introducing numpy

Benno Evers 8 years ago
parent
commit
2ce9760d71
4 changed files with 59 additions and 44 deletions
  1. 3 3
      Makefile
  2. 15 15
      README.md
  3. 1 1
      examples/minimal.cpp
  4. 40 25
      matplotlibcpp.h

+ 3 - 3
Makefile

@@ -1,11 +1,11 @@
 examples: minimal basic modern
 examples: minimal basic modern
 
 
 minimal: examples/minimal.cpp matplotlibcpp.h
 minimal: examples/minimal.cpp matplotlibcpp.h
-	cd examples && g++ minimal.cpp -lpython2.7 -o minimal -std=c++11
+	cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python2.7 -lpython2.7 -o minimal -std=c++11
 
 
 basic: examples/basic.cpp matplotlibcpp.h
 basic: examples/basic.cpp matplotlibcpp.h
-	cd examples && g++ basic.cpp -lpython2.7 -o basic
+	cd examples && g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 -o basic
 
 
 modern: examples/modern.cpp matplotlibcpp.h
 modern: examples/modern.cpp matplotlibcpp.h
-	cd examples && g++ modern.cpp -lpython2.7 -o modern -std=c++11
+	cd examples && g++ modern.cpp -I/usr/include/python2.7 -lpython2.7 -o modern -std=c++11
 
 

+ 15 - 15
README.md

@@ -17,7 +17,7 @@ Complete minimal example:
         plt::show();
         plt::show();
     }
     }
     
     
-    // g++ minimal.cpp -std=c++11 -lpython2.7
+    // g++ minimal.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7
 
 
 Result: ![Minimal example](./examples/minimal.png)
 Result: ![Minimal example](./examples/minimal.png)
 
 
@@ -54,7 +54,7 @@ A more comprehensive example:
         plt::save("./basic.png");
         plt::save("./basic.png");
     }
     }
 
 
-    // g++ basic.cpp -lpython2.7
+    // g++ basic.cpp -I/usr/include/python2.7 -lpython2.7
 
 
 Result: ![Basic example](./examples/basic.png)
 Result: ![Basic example](./examples/basic.png)
 
 
@@ -87,37 +87,39 @@ matplotlib-cpp doesn't require C++11, but will enable some additional syntactic
         plt::show();
         plt::show();
     } 
     } 
     
     
-    // g++ modern.cpp -std=c++11 -lpython
+    // g++ modern.cpp -std=c++11 -I/usr/include/python2.7 -lpython
 
 
 Result: ![Modern example](./examples/modern.png)
 Result: ![Modern example](./examples/modern.png)
 
 
 Installation
 Installation
 ------------
 ------------
+
 matplotlib-cpp works by wrapping the popular python plotting library matplotlib. (matplotlib.org)
 matplotlib-cpp works by wrapping the popular python plotting library matplotlib. (matplotlib.org)
 This means you have to have a working python installation, including development headers.
 This means you have to have a working python installation, including development headers.
 On Ubuntu:
 On Ubuntu:
 
 
-    sudo aptitude install python-matplotlib python2.7-dev
+    sudo aptitude install python-matplotlib python-numpy python2.7-dev
+
+If, for some reason, you're unable to get a working installation of numpy on your system,
+you can add the define `WITHOUT_NUMPY` to erase this dependency.
 
 
 The C++-part of the library consists of the single header file `matplotlibcpp.h` which can be placed
 The C++-part of the library consists of the single header file `matplotlibcpp.h` which can be placed
 anywhere.
 anywhere.
+
 Since a python interpreter is opened internally, it is necessary to link against `libpython2.7` in order to use
 Since a python interpreter is opened internally, it is necessary to link against `libpython2.7` in order to use
 matplotlib-cpp.
 matplotlib-cpp.
 
 
 # Python 3
 # Python 3
 
 
-The code is written in a way that should support both python2 and python3.
-By default, matplotlib-cpp will try to "just work" and include the header `python2.7/Python.h`.
+This library supports both python2 and python3 (although the python3 support is probably far less tested,
+so it is recommended to prefer python2.7). To switch the used python version, simply change
+the compiler flags accordingly.
 
 
-To modify this behaviour the define `MATPLOTLIBCPP_PYTHON_HEADER`,
-can be set to an absolute or relative path: 
+    g++ example.cpp -I/usr/include/python3.6 -lpython3.6
 
 
-     #define MATPLOTLIBCPP_PYTHON_HEADER /usr/include/python3.6/Python.h
-     #include "matplotlibcpp.h"
+The same technique can be used for linking against a custom build of python
 
 
-or
-
-    g++ -DMATPLOTLIBCPP_PYTHON_HEADER=Python.h -I/usr/include/python3.6 <...>
+    g++ example.cpp -I/usr/local/include/fancy-python4 -L/usr/local/lib -lfancy-python4
 
 
 
 
 Why?
 Why?
@@ -152,7 +154,5 @@ Todo/Issues/Wishlist
 * Right now, only a small subset of matplotlibs functionality is exposed. Stuff like xlabel()/ylabel() etc. should
 * Right now, only a small subset of matplotlibs functionality is exposed. Stuff like xlabel()/ylabel() etc. should
   be easy to add.
   be easy to add.
 
 
-* A lot of copying could be avoided if we generate numpy arrays directly instead of python lists
-
 * If you use Anaconda on Windows, you might need to set PYTHONHOME to Anaconda home directory and QT_QPA_PLATFORM_PLUGIN_PATH to %PYTHONHOME%Library/plugins/platforms. The latter is for especially when you get the error which says 'This application failed to start because it could not find or load the Qt platform plugin "windows"
 * If you use Anaconda on Windows, you might need to set PYTHONHOME to Anaconda home directory and QT_QPA_PLATFORM_PLUGIN_PATH to %PYTHONHOME%Library/plugins/platforms. The latter is for especially when you get the error which says 'This application failed to start because it could not find or load the Qt platform plugin "windows"
 in "".'
 in "".'

+ 1 - 1
examples/minimal.cpp

@@ -3,6 +3,6 @@
 namespace plt = matplotlibcpp;
 namespace plt = matplotlibcpp;
 
 
 int main() {
 int main() {
-    plt::plot({1,2,3,4});
+    plt::plot({1,3,2,4});
     plt::show();
     plt::show();
 }
 }

+ 40 - 25
matplotlibcpp.h

@@ -6,26 +6,23 @@
 #include <algorithm>
 #include <algorithm>
 #include <stdexcept>
 #include <stdexcept>
 #include <iostream>
 #include <iostream>
+#include <stdint.h> // <cstdint> requires c++11 support
 
 
 #if __cplusplus > 199711L || _MSC_VER > 1800
 #if __cplusplus > 199711L || _MSC_VER > 1800
 #include <functional>
 #include <functional>
 #endif
 #endif
 
 
-// i.e. g++ -DMATPLOTLIBCPP_PYTHON_HEADER=/usr/include/python3.6/Python.h [...]
-#ifdef MATPLOTLIBCPP_PYTHON_HEADER
-#define STRINGIFY_(x) #x
-#define STRINGIFY(x) STRINGIFY_(x)
-#include STRINGIFY(MATPLOTLIBCPP_PYTHON_HEADER)
-#else // This should stay the default for backwards compatibility
-#include <python2.7/Python.h>
-#endif
+#include <Python.h>
+
+#ifndef WITHOUT_NUMPY
+  #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+  #include <numpy/arrayobject.h>
+#endif // WITHOUT_NUMPY
 
 
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
 #define PyString_FromString PyUnicode_FromString
 #define PyString_FromString PyUnicode_FromString
 #endif
 #endif
 
 
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
-#include <numpy/arrayobject.h>
 
 
 namespace matplotlibcpp {
 namespace matplotlibcpp {
 
 
@@ -68,14 +65,16 @@ namespace matplotlibcpp {
                 
                 
                 // optional but recommended
                 // optional but recommended
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
-                wchar_t name[] = L"plotting";
+				wchar_t name[] = L"plotting";
 #else
 #else
-                char name[] = "plotting";
+				char name[] = "plotting";
 #endif
 #endif
 				Py_SetProgramName(name);
 				Py_SetProgramName(name);
 				Py_Initialize();
 				Py_Initialize();
 
 
+#ifndef WITHOUT_NUMPY
 				import_array(); // initialize numpy C-API
 				import_array(); // initialize numpy C-API
+#endif
 
 
 				PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
 				PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
 				PyObject* pylabname  = PyString_FromString("pylab");
 				PyObject* pylabname  = PyString_FromString("pylab");
@@ -182,19 +181,21 @@ namespace matplotlibcpp {
 
 
 		return res;
 		return res;
 	}
 	}
+
+#ifndef WITHOUT_NUMPY
 	// Type selector for numpy array conversion
 	// Type selector for numpy array conversion
 	template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
 	template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
 	template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
 	template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
 	template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
 	template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
 	template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
 	template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
-	template <> struct select_npy_type<std::int8_t> { const static NPY_TYPES type = NPY_INT8; };
-	template <> struct select_npy_type<std::int16_t> { const static NPY_TYPES type = NPY_SHORT; };
-	template <> struct select_npy_type<std::int32_t> { const static NPY_TYPES type = NPY_INT; };
-	template <> struct select_npy_type<std::int64_t> { const static NPY_TYPES type = NPY_INT64; };
-	template <> struct select_npy_type<std::uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
-	template <> struct select_npy_type<std::uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
-	template <> struct select_npy_type<std::uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
-	template <> struct select_npy_type<std::uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
+	template <> struct select_npy_type<int8_t> { const static NPY_TYPES type = NPY_INT8; };
+	template <> struct select_npy_type<int16_t> { const static NPY_TYPES type = NPY_SHORT; };
+	template <> struct select_npy_type<int32_t> { const static NPY_TYPES type = NPY_INT; };
+	template <> struct select_npy_type<int64_t> { const static NPY_TYPES type = NPY_INT64; };
+	template <> struct select_npy_type<uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
+	template <> struct select_npy_type<uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
+	template <> struct select_npy_type<uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
+	template <> struct select_npy_type<uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
 
 
 	template<typename Numeric>
 	template<typename Numeric>
 	PyObject* get_array(const std::vector<Numeric>& v)
 	PyObject* get_array(const std::vector<Numeric>& v)
@@ -203,11 +204,11 @@ namespace matplotlibcpp {
 		NPY_TYPES type = select_npy_type<Numeric>::type; 
 		NPY_TYPES type = select_npy_type<Numeric>::type; 
 		if (type == NPY_NOTYPE)
 		if (type == NPY_NOTYPE)
 		{
 		{
-				std::vector<double> vd(v.size());
-				npy_intp vsize = v.size();
-				std::copy(v.begin(),v.end(),vd.begin());
-				PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
-				return varray;
+			std::vector<double> vd(v.size());
+			npy_intp vsize = v.size();
+			std::copy(v.begin(),v.end(),vd.begin());
+			PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
+			return varray;
 		}
 		}
 
 
 		npy_intp vsize = v.size();
 		npy_intp vsize = v.size();
@@ -215,6 +216,20 @@ namespace matplotlibcpp {
 		return varray;
 		return varray;
 	}
 	}
 
 
+#else // fallback if we don't have numpy: copy every element of the given vector
+
+	template<typename Numeric>
+	PyObject* get_array(const std::vector<Numeric>& v)
+	{
+		PyObject* list = PyList_New(v.size());
+		for(size_t i = 0; i < v.size(); ++i) {
+			PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
+		}
+		return list;
+	}
+
+#endif // WITHOUT_NUMPY
+
 	template<typename Numeric>
 	template<typename Numeric>
 	bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
 	bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
 	{
 	{