Kaynağa Gözat

Update documentation after introducing numpy

Benno Evers 8 yıl önce
ebeveyn
işleme
2ce9760d71
4 değiştirilmiş dosya ile 59 ekleme ve 44 silme
  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
 
 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
-	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
-	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();
     }
     
-    // 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)
 
@@ -54,7 +54,7 @@ A more comprehensive example:
         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)
 
@@ -87,37 +87,39 @@ matplotlib-cpp doesn't require C++11, but will enable some additional syntactic
         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)
 
 Installation
 ------------
+
 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.
 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
 anywhere.
+
 Since a python interpreter is opened internally, it is necessary to link against `libpython2.7` in order to use
 matplotlib-cpp.
 
 # 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?
@@ -152,7 +154,5 @@ Todo/Issues/Wishlist
 * Right now, only a small subset of matplotlibs functionality is exposed. Stuff like xlabel()/ylabel() etc. should
   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"
 in "".'

+ 1 - 1
examples/minimal.cpp

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

+ 40 - 25
matplotlibcpp.h

@@ -6,26 +6,23 @@
 #include <algorithm>
 #include <stdexcept>
 #include <iostream>
+#include <stdint.h> // <cstdint> requires c++11 support
 
 #if __cplusplus > 199711L || _MSC_VER > 1800
 #include <functional>
 #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
 #define PyString_FromString PyUnicode_FromString
 #endif
 
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
-#include <numpy/arrayobject.h>
 
 namespace matplotlibcpp {
 
@@ -68,14 +65,16 @@ namespace matplotlibcpp {
                 
                 // optional but recommended
 #if PY_MAJOR_VERSION >= 3
-                wchar_t name[] = L"plotting";
+				wchar_t name[] = L"plotting";
 #else
-                char name[] = "plotting";
+				char name[] = "plotting";
 #endif
 				Py_SetProgramName(name);
 				Py_Initialize();
 
+#ifndef WITHOUT_NUMPY
 				import_array(); // initialize numpy C-API
+#endif
 
 				PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
 				PyObject* pylabname  = PyString_FromString("pylab");
@@ -182,19 +181,21 @@ namespace matplotlibcpp {
 
 		return res;
 	}
+
+#ifndef WITHOUT_NUMPY
 	// Type selector for numpy array conversion
 	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<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<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>
 	PyObject* get_array(const std::vector<Numeric>& v)
@@ -203,11 +204,11 @@ namespace matplotlibcpp {
 		NPY_TYPES type = select_npy_type<Numeric>::type; 
 		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();
@@ -215,6 +216,20 @@ namespace matplotlibcpp {
 		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>
 	bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
 	{