Squashed 'third_party/matplotlib-cpp/' content from commit f994996

Change-Id: I2124d6ed85284acca42fc0e90f489f422e6e440a
git-subtree-dir: third_party/matplotlib-cpp
git-subtree-split: f994996e0724f30612154a26cbdc660ad9c51907
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7622be7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+# Logfiles
+*.tlog
+*.log
+
+# Build
+/examples/build/*
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a67f2b5
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Benno Evers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/LICENSE.matplotlib b/LICENSE.matplotlib
new file mode 100644
index 0000000..1c1a66b
--- /dev/null
+++ b/LICENSE.matplotlib
@@ -0,0 +1,47 @@
+This library does not contain any files from the matplotlib project, nor
+does it make any changes to it. On the other hand, the code contained herein
+is perfectly useless without a separate installation of matplotlib.
+I don't know enough about US copyright law to decide whether this implies
+that this library "uses" or is "based on" matplotlib.
+In any case, matplotlib comes with the following license:
+
+License agreement for matplotlib 1.4.3
+1. This LICENSE AGREEMENT is between the Matplotlib Development Team (“MDT”),
+   and the Individual or Organization (“Licensee”) accessing and otherwise
+   using matplotlib software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, MDT hereby grants
+   Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze,
+   test, perform and/or display publicly, prepare derivative works, distribute, and
+   otherwise use matplotlib 1.4.3 alone or in any derivative version, provided, however,
+   that MDT’s License Agreement and MDT’s notice of copyright, i.e.,
+   “Copyright (c) 2012-2013 Matplotlib Development Team; All Rights Reserved” are retained
+   in matplotlib 1.4.3 alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or incorporates
+   matplotlib 1.4.3 or any part thereof, and wants to make the derivative work available
+   to others as provided herein, then Licensee hereby agrees to include in any such work a
+   brief summary of the changes made to matplotlib 1.4.3.
+
+4. MDT is making matplotlib 1.4.3 available to Licensee on an “AS IS” basis. MDT MAKES NO
+   REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION,
+   MDT MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+   FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 1.4.3 WILL NOT INFRINGE ANY
+   THIRD PARTY RIGHTS.
+
+5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB 1.4.3 FOR ANY
+   INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING,
+   DISTRIBUTING, OR OTHERWISE USING MATPLOTLIB 1.4.3, OR ANY DERIVATIVE THEREOF,
+   EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+   its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship of
+   agency, partnership, or joint venture between MDT and Licensee. This License
+   Agreement does not grant permission to use MDT trademarks or trade name in a
+   trademark sense to endorse or promote products or services of Licensee, or any
+   third party.
+
+8. By copying, installing or otherwise using matplotlib 1.4.3, Licensee agrees to be
+   bound by the terms and conditions of this License Agreement.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e75d134
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
+examples: minimal basic modern animation nonblock xkcd
+
+minimal: examples/minimal.cpp matplotlibcpp.h
+	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 -I/usr/include/python2.7 -lpython2.7 -o basic
+
+modern: examples/modern.cpp matplotlibcpp.h
+	cd examples && g++ modern.cpp -I/usr/include/python2.7 -lpython2.7 -o modern -std=c++11
+
+animation: examples/animation.cpp matplotlibcpp.h
+	cd examples && g++ animation.cpp -I/usr/include/python2.7 -lpython2.7 -o animation -std=c++11
+
+nonblock: examples/nonblock.cpp matplotlibcpp.h
+	cd examples && g++ nonblock.cpp -I/usr/include/python2.7 -lpython2.7 -o nonblock -std=c++11
+
+xkcd: examples/xkcd.cpp matplotlibcpp.h
+	cd examples && g++ xkcd.cpp -I/usr/include/python2.7 -lpython2.7 -o xkcd -std=c++11
+
+clean:
+	rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e0d74ba
--- /dev/null
+++ b/README.md
@@ -0,0 +1,199 @@
+matplotlib-cpp
+==============
+
+Welcome to matplotlib-cpp, possibly the simplest C++ plotting library.
+It is built to resemble the plotting API used by Matlab and matplotlib.
+
+
+
+Usage
+-----
+Complete minimal example:
+```cpp
+#include "matplotlibcpp.h"
+namespace plt = matplotlibcpp;
+int main() {
+    plt::plot({1,3,2,4});
+    plt::show();
+}
+```
+    g++ minimal.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7
+
+**Result:**
+
+![Minimal example](./examples/minimal.png)
+
+A more comprehensive example:
+```cpp
+#include "matplotlibcpp.h"
+#include <cmath>
+
+namespace plt = matplotlibcpp;
+
+int main() 
+{
+    // Prepare data.
+    int n = 5000;
+    std::vector<double> x(n), y(n), z(n), w(n,2);
+    for(int i=0; i<n; ++i) {
+        x.at(i) = i*i;
+        y.at(i) = sin(2*M_PI*i/360.0);
+        z.at(i) = log(i);
+    }
+
+    // Plot line from given x and y data. Color is selected automatically.
+    plt::plot(x, y);
+    // Plot a red dashed line from given x and y data.
+    plt::plot(x, w,"r--");
+    // Plot a line whose name will show up as "log(x)" in the legend.
+    plt::named_plot("log(x)", x, z);
+
+    // Set x-axis to interval [0,1000000]
+    plt::xlim(0, 1000*1000);
+    // Enable legend.
+    plt::legend();
+    // Save the image (file format is determined by the extension)
+    plt::save("./basic.png");
+}
+```
+    g++ basic.cpp -I/usr/include/python2.7 -lpython2.7
+
+Result: ![Basic example](./examples/basic.png)
+
+matplotlib-cpp doesn't require C++11, but will enable some additional syntactic sugar when available:
+```cpp
+#include <cmath>
+#include "matplotlibcpp.h"
+
+using namespace std;
+namespace plt = matplotlibcpp;
+
+int main() 
+{    
+    // Prepare data.
+    int n = 5000; // number of data points
+    vector<double> x(n),y(n); 
+    for(int i=0; i<n; ++i) {
+        double t = 2*M_PI*i/n;
+        x.at(i) = 16*sin(t)*sin(t)*sin(t);
+        y.at(i) = 13*cos(t) - 5*cos(2*t) - 2*cos(3*t) - cos(4*t);
+    }
+
+    // plot() takes an arbitrary number of (x,y,format)-triples. 
+    // x must be iterable (that is, anything providing begin(x) and end(x)),
+    // y must either be callable (providing operator() const) or iterable. 
+    plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-");
+
+
+    // show plots
+    plt::show();
+} 
+```
+    g++ modern.cpp -std=c++11 -I/usr/include/python2.7 -lpython
+
+Result: ![Modern example](./examples/modern.png)
+
+Or some *funny-looking xkcd-styled* example:
+```cpp
+#include "matplotlibcpp.h"
+#include <vector>
+#include <cmath>
+
+namespace plt = matplotlibcpp;
+
+int main() {
+    std::vector<double> t(1000);
+    std::vector<double> x(t.size());
+
+    for(size_t i = 0; i < t.size(); i++) {
+        t[i] = i / 100.0;
+        x[i] = sin(2.0 * M_PI * 1.0 * t[i]);
+    }
+
+    plt::xkcd();
+    plt::plot(t, x);
+    plt::title("AN ORDINARY SIN WAVE");
+    plt::save("xkcd.png");
+}
+
+```
+    g++ xkcd.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7
+
+**Result:**
+
+![Minimal example](./examples/xkcd.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 apt-get 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.
+
+# CMake
+
+If you prefer to use CMake as build system, you will want to add something like this to your
+CMakeLists.txt:
+```cmake
+find_package(PythonLibs 2.7)
+target_include_directories(myproject PRIVATE ${PYTHON_INCLUDE_DIRS})
+target_link_libraries(myproject ${PYTHON_LIBRARIES})
+```
+# Python 3
+
+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.
+
+    g++ example.cpp -I/usr/include/python3.6 -lpython3.6
+
+The same technique can be used for linking against a custom build of python
+
+    g++ example.cpp -I/usr/local/include/fancy-python4 -L/usr/local/lib -lfancy-python4
+
+
+Why?
+----
+I initially started this library during my diploma thesis. The usual approach of 
+writing data from the c++ algorithm to a file and afterwards parsing and plotting
+it in python using matplotlib proved insufficient: Keeping the algorithm
+and plotting code in sync requires a lot of effort when the C++ code frequently and substantially 
+changes. Additionally, the python yaml parser was not able to cope with files that
+exceed a few hundred megabytes in size.
+
+Therefore, I was looking for a C++ plotting library that was extremely easy to use
+and to add into an existing codebase, preferrably header-only. When I found
+none, I decided to write one myself, which is basically a C++ wrapper around
+matplotlib. As you can see from the above examples, plotting data and saving it
+to an image file can be done as few as two lines of code.
+
+The general approach of providing a simple C++ API for utilizing python code
+was later generalized and extracted into a separate, more powerful
+library in another project of mine, [wrappy](http://www.github.com/lava/wrappy).
+
+
+Todo/Issues/Wishlist
+--------------------
+* This library is not thread safe. Protect all concurrent access with a mutex.
+  Sadly, this is not easy to fix since it is not caused by the library itself but
+  by the python interpreter, which is itself not thread-safe.
+
+* It would be nice to have a more object-oriented design with a Plot class which would allow
+  multiple independent plots per program.
+
+* Right now, only a small subset of matplotlibs functionality is exposed. Stuff like xlabel()/ylabel() etc. should
+  be easy to add.
+
+* 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 "".'
diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt
new file mode 100644
index 0000000..ba14b86
--- /dev/null
+++ b/contrib/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.1)
+project (MatplotlibCPP_Test)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+include_directories(${PYTHONHOME}/include)
+link_directories(${PYTHONHOME}/libs)
+
+add_definitions(-DMATPLOTLIBCPP_PYTHON_HEADER=Python.h)
+
+# message(STATUS "*** dump start cmake variables ***")
+# get_cmake_property(_variableNames VARIABLES)
+# foreach(_variableName ${_variableNames})
+        # message(STATUS "${_variableName}=${${_variableName}}")
+# endforeach()
+# message(STATUS "*** dump end ***")
+
+add_executable(minimal ${CMAKE_CURRENT_SOURCE_DIR}/../examples/minimal.cpp)
+add_executable(basic ${CMAKE_CURRENT_SOURCE_DIR}/../examples/basic.cpp)
+add_executable(modern ${CMAKE_CURRENT_SOURCE_DIR}/../examples/modern.cpp)
diff --git a/contrib/README.md b/contrib/README.md
new file mode 100644
index 0000000..efc0a50
--- /dev/null
+++ b/contrib/README.md
@@ -0,0 +1,19 @@
+# contrib/
+
+This folder contains contributions that may be useful to users of this library, but
+have a too specialized audience to become part of the main tree.
+
+In particular, things in here will have a higher rate of bit-rot, since
+contributors are not required to and may be unable to check whether their
+changes break any of them.
+
+## Windows support
+
+### Configuring and Building Samples
+
+```cmd
+> cd contrib
+> WinBuild.cmd
+```
+
+The `WinBuild.cmd` will set up temporal ENV variables and build binaries in (matplotlib root)/examples with the Release configuration.
diff --git a/contrib/WinBuild.cmd b/contrib/WinBuild.cmd
new file mode 100644
index 0000000..4e3b450
--- /dev/null
+++ b/contrib/WinBuild.cmd
@@ -0,0 +1,46 @@
+@echo off
+@setlocal EnableDelayedExpansion
+
+if NOT DEFINED MSVC_VERSION set MSVC_VERSION=14
+if NOT DEFINED CMAKE_CONFIG set CMAKE_CONFIG=Release
+if NOT DEFINED PYTHONHOME   set PYTHONHOME=C:/Users/%username%/Anaconda3
+
+if "%MSVC_VERSION%"=="14" (
+    if "%processor_architecture%" == "AMD64" (
+        set CMAKE_GENERATOR=Visual Studio 14 2015 Win64
+    ) else (
+        set CMAKE_GENERATOR=Visual Studio 14 2015
+    )
+) else if "%MSVC_VERSION%"=="12" (
+    if "%processor_architecture%" == "AMD64" (
+        set CMAKE_GENERATOR=Visual Studio 12 2013 Win64
+    
+    ) else (
+        set CMAKE_GENERATOR=Visual Studio 12 2013
+    )
+)
+
+set batch_file=!VS%MSVC_VERSION%0COMNTOOLS!..\..\VC\vcvarsall.bat
+call "%batch_file%" %processor_architecture%
+
+pushd ..
+pushd examples
+if NOT EXIST build mkdir build
+pushd build
+
+cmake -G"!CMAKE_GENERATOR!" ^
+      -DPYTHONHOME:STRING=%PYTHONHOME%^
+      -DCMAKE_BUILD_TYPE:STRING=%CMAKE_CONFIG% ^
+      %~dp0
+cmake --build . --config %CMAKE_CONFIG%  
+
+pushd %CMAKE_CONFIG%  
+if not EXIST platforms mkdir platforms
+if EXIST %PYTHONHOME%/Library/plugins/platforms/qwindows.dll ^
+cp %PYTHONHOME%/Library/plugins/platforms/qwindows.dll ./platforms/
+popd
+REM move ./%CMAKE_CONFIG% ../
+popd
+popd
+popd
+@endlocal
diff --git a/examples/animation.cpp b/examples/animation.cpp
new file mode 100644
index 0000000..d979430
--- /dev/null
+++ b/examples/animation.cpp
@@ -0,0 +1,36 @@
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include "../matplotlibcpp.h"
+
+namespace plt = matplotlibcpp;
+
+int main()
+{
+	int n = 1000;
+	std::vector<double> x, y, z;
+
+	for(int i=0; i<n; i++) {
+		x.push_back(i*i);
+		y.push_back(sin(2*M_PI*i/360.0));
+		z.push_back(log(i));
+
+		if (i % 10 == 0) {
+			// Clear previous plot
+			plt::clf();
+			// Plot line from given x and y data. Color is selected automatically.
+			plt::plot(x, y);
+			// Plot a line whose name will show up as "log(x)" in the legend.
+			plt::named_plot("log(x)", x, z);
+
+			// Set x-axis to interval [0,1000000]
+			plt::xlim(0, n*n);
+
+			// Add graph title
+			plt::title("Sample figure");
+			// Enable legend.
+			plt::legend();
+			// Display plot continuously
+			plt::pause(0.01);
+		}
+	}
+}
diff --git a/examples/animation.gif b/examples/animation.gif
new file mode 100644
index 0000000..ef8eb5a
--- /dev/null
+++ b/examples/animation.gif
Binary files differ
diff --git a/examples/basic.cpp b/examples/basic.cpp
new file mode 100644
index 0000000..2b02f27
--- /dev/null
+++ b/examples/basic.cpp
@@ -0,0 +1,37 @@
+#define _USE_MATH_DEFINES
+#include <iostream>
+#include <cmath>
+#include "../matplotlibcpp.h"
+
+namespace plt = matplotlibcpp;
+
+int main() 
+{
+	// Prepare data.
+	int n = 5000;
+	std::vector<double> x(n), y(n), z(n), w(n,2);
+	for(int i=0; i<n; ++i) {
+		x.at(i) = i*i;
+		y.at(i) = sin(2*M_PI*i/360.0);
+		z.at(i) = log(i);
+	}
+
+	// Plot line from given x and y data. Color is selected automatically.
+	plt::plot(x, y);
+	// Plot a red dashed line from given x and y data.
+	plt::plot(x, w,"r--");
+	// Plot a line whose name will show up as "log(x)" in the legend.
+	plt::named_plot("log(x)", x, z);
+
+	// Set x-axis to interval [0,1000000]
+	plt::xlim(0, 1000*1000);
+
+	// Add graph title
+	plt::title("Sample figure");
+	// Enable legend.
+	plt::legend();
+	// save figure
+	const char* filename = "./basic.png";
+	std::cout << "Saving result to " << filename << std::endl;;
+	plt::save(filename);
+}
diff --git a/examples/basic.png b/examples/basic.png
new file mode 100644
index 0000000..eef82a2
--- /dev/null
+++ b/examples/basic.png
Binary files differ
diff --git a/examples/minimal.cpp b/examples/minimal.cpp
new file mode 100644
index 0000000..fbe1e1c
--- /dev/null
+++ b/examples/minimal.cpp
@@ -0,0 +1,8 @@
+#include "../matplotlibcpp.h"
+
+namespace plt = matplotlibcpp;
+
+int main() {
+    plt::plot({1,3,2,4});
+    plt::show();
+}
diff --git a/examples/minimal.png b/examples/minimal.png
new file mode 100644
index 0000000..0f6cf37
--- /dev/null
+++ b/examples/minimal.png
Binary files differ
diff --git a/examples/modern.cpp b/examples/modern.cpp
new file mode 100644
index 0000000..a8aa0c7
--- /dev/null
+++ b/examples/modern.cpp
@@ -0,0 +1,30 @@
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include "../matplotlibcpp.h"
+
+using namespace std;
+namespace plt = matplotlibcpp;
+
+int main() 
+{
+	// plot(y) - the x-coordinates are implicitly set to [0,1,...,n)
+	//plt::plot({1,2,3,4}); 
+	
+	// Prepare data for parametric plot.
+	int n = 5000; // number of data points
+	vector<double> x(n),y(n); 
+	for(int i=0; i<n; ++i) {
+		double t = 2*M_PI*i/n;
+		x.at(i) = 16*sin(t)*sin(t)*sin(t);
+		y.at(i) = 13*cos(t) - 5*cos(2*t) - 2*cos(3*t) - cos(4*t);
+	}
+
+	// plot() takes an arbitrary number of (x,y,format)-triples. 
+	// x must be iterable (that is, anything providing begin(x) and end(x)),
+	// y must either be callable (providing operator() const) or iterable. 
+	plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-");
+
+
+	// show plots
+	plt::show();
+}
diff --git a/examples/modern.png b/examples/modern.png
new file mode 100644
index 0000000..0c51555
--- /dev/null
+++ b/examples/modern.png
Binary files differ
diff --git a/examples/nonblock.cpp b/examples/nonblock.cpp
new file mode 100644
index 0000000..327d96c
--- /dev/null
+++ b/examples/nonblock.cpp
@@ -0,0 +1,46 @@
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include "../matplotlibcpp.h"
+
+namespace plt = matplotlibcpp;
+
+
+using namespace matplotlibcpp;
+using namespace std;
+
+int main()
+{
+    // Prepare data.
+    int n = 5000;
+    std::vector<double> x(n), y(n), z(n), w(n,2);
+    for(int i=0; i<n; ++i) {
+        x.at(i) = i*i;
+        y.at(i) = sin(2*M_PI*i/360.0);
+        z.at(i) = log(i);
+    }
+
+    // Plot line from given x and y data. Color is selected automatically.
+    plt::subplot(2,2,1);
+    plt::plot(x, y);
+
+    // Plot a red dashed line from given x and y data.
+    plt::subplot(2,2,2);
+    plt::plot(x, w,"r--");
+
+    // Plot a line whose name will show up as "log(x)" in the legend.
+    plt::subplot(2,2,3);
+    plt::named_plot("log(x)", x, z);
+
+    // Set x-axis to interval [0,1000000]
+    plt::xlim(0, 1000*1000);
+
+    // Add graph title
+    plt::title("Sample figure");
+    // Enable legend.
+    plt::legend();
+
+    plt::show(false);
+
+    cout << "matplotlibcpp::show() is working in an non-blocking mode" << endl;
+    getchar();
+}
diff --git a/examples/xkcd.cpp b/examples/xkcd.cpp
new file mode 100644
index 0000000..9bf6454
--- /dev/null
+++ b/examples/xkcd.cpp
@@ -0,0 +1,21 @@
+#include "../matplotlibcpp.h"
+#include <vector>
+#include <cmath>
+
+namespace plt = matplotlibcpp;
+
+int main() {
+    std::vector<double> t(1000);
+    std::vector<double> x(t.size());
+
+    for(size_t i = 0; i < t.size(); i++) {
+        t[i] = i / 100.0;
+        x[i] = sin(2.0 * M_PI * 1.0 * t[i]);
+    }
+
+    plt::xkcd();
+    plt::plot(t, x);
+    plt::title("AN ORDINARY SIN WAVE");
+    plt::show();
+}
+
diff --git a/examples/xkcd.png b/examples/xkcd.png
new file mode 100644
index 0000000..c285e3d
--- /dev/null
+++ b/examples/xkcd.png
Binary files differ
diff --git a/matplotlibcpp.h b/matplotlibcpp.h
new file mode 100644
index 0000000..95d3772
--- /dev/null
+++ b/matplotlibcpp.h
@@ -0,0 +1,1164 @@
+#pragma once
+
+#include <vector>
+#include <map>
+#include <numeric>
+#include <algorithm>
+#include <stdexcept>
+#include <iostream>
+#include <stdint.h> // <cstdint> requires c++11 support
+
+#if __cplusplus > 199711L || _MSC_VER > 1800
+#  include <functional>
+#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
+
+
+namespace matplotlibcpp {
+namespace detail {
+
+static std::string s_backend;
+
+struct _interpreter {
+    PyObject *s_python_function_show;
+    PyObject *s_python_function_close;
+    PyObject *s_python_function_draw;
+    PyObject *s_python_function_pause;
+    PyObject *s_python_function_save;
+    PyObject *s_python_function_figure;
+    PyObject *s_python_function_plot;
+    PyObject *s_python_function_semilogx;
+    PyObject *s_python_function_semilogy;
+    PyObject *s_python_function_loglog;
+    PyObject *s_python_function_fill_between;
+    PyObject *s_python_function_hist;
+    PyObject *s_python_function_subplot;
+    PyObject *s_python_function_legend;
+    PyObject *s_python_function_xlim;
+    PyObject *s_python_function_ion;
+    PyObject *s_python_function_ylim;
+    PyObject *s_python_function_title;
+    PyObject *s_python_function_axis;
+    PyObject *s_python_function_xlabel;
+    PyObject *s_python_function_ylabel;
+    PyObject *s_python_function_grid;
+    PyObject *s_python_function_clf;
+    PyObject *s_python_function_errorbar;
+    PyObject *s_python_function_annotate;
+    PyObject *s_python_function_tight_layout;
+    PyObject *s_python_empty_tuple;
+    PyObject *s_python_function_stem;
+    PyObject *s_python_function_xkcd;
+
+    /* For now, _interpreter is implemented as a singleton since its currently not possible to have
+       multiple independent embedded python interpreters without patching the python source code
+       or starting a separate process for each.
+        http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
+       */
+
+    static _interpreter& get() {
+        static _interpreter ctx;
+        return ctx;
+    }
+
+private:
+
+#ifndef WITHOUT_NUMPY
+#  if PY_MAJOR_VERSION >= 3
+
+    void *import_numpy() {
+        import_array(); // initialize C-API
+        return NULL;
+    }
+
+#  else
+
+    void import_numpy() {
+        import_array(); // initialize C-API
+    }
+
+#  endif
+#endif
+
+    _interpreter() {
+
+        // optional but recommended
+#if PY_MAJOR_VERSION >= 3
+        wchar_t name[] = L"plotting";
+#else
+        char name[] = "plotting";
+#endif
+        Py_SetProgramName(name);
+        Py_Initialize();
+
+#ifndef WITHOUT_NUMPY
+        import_numpy(); // initialize numpy C-API
+#endif
+
+        PyObject* matplotlibname = PyString_FromString("matplotlib");
+        PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
+        PyObject* pylabname  = PyString_FromString("pylab");
+        if (!pyplotname || !pylabname || !matplotlibname) {
+            throw std::runtime_error("couldnt create string");
+        }
+
+        PyObject* matplotlib = PyImport_Import(matplotlibname);
+        Py_DECREF(matplotlibname);
+        if (!matplotlib) { throw std::runtime_error("Error loading module matplotlib!"); }
+
+        // matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
+        // or matplotlib.backends is imported for the first time
+        if (!s_backend.empty()) {
+            PyObject_CallMethod(matplotlib, const_cast<char*>("use"), const_cast<char*>("s"), s_backend.c_str());
+        }
+
+        PyObject* pymod = PyImport_Import(pyplotname);
+        Py_DECREF(pyplotname);
+        if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); }
+
+
+        PyObject* pylabmod = PyImport_Import(pylabname);
+        Py_DECREF(pylabname);
+        if (!pylabmod) { throw std::runtime_error("Error loading module pylab!"); }
+
+        s_python_function_show = PyObject_GetAttrString(pymod, "show");
+        s_python_function_close = PyObject_GetAttrString(pymod, "close");
+        s_python_function_draw = PyObject_GetAttrString(pymod, "draw");
+        s_python_function_pause = PyObject_GetAttrString(pymod, "pause");
+        s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
+        s_python_function_plot = PyObject_GetAttrString(pymod, "plot");
+        s_python_function_semilogx = PyObject_GetAttrString(pymod, "semilogx");
+        s_python_function_semilogy = PyObject_GetAttrString(pymod, "semilogy");
+        s_python_function_loglog = PyObject_GetAttrString(pymod, "loglog");
+        s_python_function_fill_between = PyObject_GetAttrString(pymod, "fill_between");
+        s_python_function_hist = PyObject_GetAttrString(pymod,"hist");
+        s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot");
+        s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
+        s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim");
+        s_python_function_title = PyObject_GetAttrString(pymod, "title");
+        s_python_function_axis = PyObject_GetAttrString(pymod, "axis");
+        s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel");
+        s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel");
+        s_python_function_grid = PyObject_GetAttrString(pymod, "grid");
+        s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim");
+        s_python_function_ion = PyObject_GetAttrString(pymod, "ion");
+        s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig");
+        s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate");
+        s_python_function_clf = PyObject_GetAttrString(pymod, "clf");
+        s_python_function_errorbar = PyObject_GetAttrString(pymod, "errorbar");
+        s_python_function_tight_layout = PyObject_GetAttrString(pymod, "tight_layout");
+        s_python_function_stem = PyObject_GetAttrString(pymod, "stem");
+        s_python_function_xkcd = PyObject_GetAttrString(pymod, "xkcd");
+
+        if(    !s_python_function_show
+            || !s_python_function_close
+            || !s_python_function_draw
+            || !s_python_function_pause
+            || !s_python_function_figure
+            || !s_python_function_plot
+            || !s_python_function_semilogx
+            || !s_python_function_semilogy
+            || !s_python_function_loglog
+            || !s_python_function_fill_between
+            || !s_python_function_subplot
+            || !s_python_function_legend
+            || !s_python_function_ylim
+            || !s_python_function_title
+            || !s_python_function_axis
+            || !s_python_function_xlabel
+            || !s_python_function_ylabel
+            || !s_python_function_grid
+            || !s_python_function_xlim
+            || !s_python_function_ion
+            || !s_python_function_save
+            || !s_python_function_clf
+            || !s_python_function_annotate
+            || !s_python_function_errorbar
+            || !s_python_function_errorbar
+            || !s_python_function_tight_layout
+            || !s_python_function_stem
+            || !s_python_function_xkcd
+        ) { throw std::runtime_error("Couldn't find required function!"); }
+
+        if (   !PyFunction_Check(s_python_function_show)
+            || !PyFunction_Check(s_python_function_close)
+            || !PyFunction_Check(s_python_function_draw)
+            || !PyFunction_Check(s_python_function_pause)
+            || !PyFunction_Check(s_python_function_figure)
+            || !PyFunction_Check(s_python_function_plot)
+            || !PyFunction_Check(s_python_function_semilogx)
+            || !PyFunction_Check(s_python_function_semilogy)
+            || !PyFunction_Check(s_python_function_loglog)
+            || !PyFunction_Check(s_python_function_fill_between)
+            || !PyFunction_Check(s_python_function_subplot)
+            || !PyFunction_Check(s_python_function_legend)
+            || !PyFunction_Check(s_python_function_annotate)
+            || !PyFunction_Check(s_python_function_ylim)
+            || !PyFunction_Check(s_python_function_title)
+            || !PyFunction_Check(s_python_function_axis)
+            || !PyFunction_Check(s_python_function_xlabel)
+            || !PyFunction_Check(s_python_function_ylabel)
+            || !PyFunction_Check(s_python_function_grid)
+            || !PyFunction_Check(s_python_function_xlim)
+            || !PyFunction_Check(s_python_function_ion)
+            || !PyFunction_Check(s_python_function_save)
+            || !PyFunction_Check(s_python_function_clf)
+            || !PyFunction_Check(s_python_function_tight_layout)
+            || !PyFunction_Check(s_python_function_errorbar)
+            || !PyFunction_Check(s_python_function_stem)
+            || !PyFunction_Check(s_python_function_xkcd)
+        ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); }
+
+        s_python_empty_tuple = PyTuple_New(0);
+    }
+
+    ~_interpreter() {
+        Py_Finalize();
+    }
+};
+
+} // end namespace detail
+
+// must be called before the first regular call to matplotlib to have any effect
+inline void backend(const std::string& name)
+{
+    detail::s_backend = name;
+}
+
+inline bool annotate(std::string annotation, double x, double y)
+{
+    PyObject * xy = PyTuple_New(2);
+    PyObject * str = PyString_FromString(annotation.c_str());
+
+    PyTuple_SetItem(xy,0,PyFloat_FromDouble(x));
+    PyTuple_SetItem(xy,1,PyFloat_FromDouble(y));
+
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "xy", xy);
+
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, str);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs);
+
+    Py_DECREF(args);
+    Py_DECREF(kwargs);
+
+    if(res) Py_DECREF(res);
+
+    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<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)
+{
+    detail::_interpreter::get();    //interpreter needs to be initialized for the numpy commands to work
+    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;
+    }
+
+    npy_intp vsize = v.size();
+    PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
+    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)
+{
+    assert(x.size() == y.size());
+
+    // using numpy arrays
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    // construct positional args
+    PyObject* args = PyTuple_New(2);
+    PyTuple_SetItem(args, 0, xarray);
+    PyTuple_SetItem(args, 1, yarray);
+
+    // construct keyword args
+    PyObject* kwargs = PyDict_New();
+    for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
+    {
+        PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
+    }
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
+
+    Py_DECREF(args);
+    Py_DECREF(kwargs);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename Numeric>
+bool stem(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
+{
+    assert(x.size() == y.size());
+
+    // using numpy arrays
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    // construct positional args
+    PyObject* args = PyTuple_New(2);
+    PyTuple_SetItem(args, 0, xarray);
+    PyTuple_SetItem(args, 1, yarray);
+
+    // construct keyword args
+    PyObject* kwargs = PyDict_New();
+    for (std::map<std::string, std::string>::const_iterator it =
+            keywords.begin(); it != keywords.end(); ++it) {
+        PyDict_SetItemString(kwargs, it->first.c_str(),
+                PyString_FromString(it->second.c_str()));
+    }
+
+    PyObject* res = PyObject_Call(
+            detail::_interpreter::get().s_python_function_stem, args, kwargs);
+
+    Py_DECREF(args);
+    Py_DECREF(kwargs);
+    if (res)
+        Py_DECREF(res);
+
+    return res;
+}
+
+template< typename Numeric >
+bool fill_between(const std::vector<Numeric>& x, const std::vector<Numeric>& y1, const std::vector<Numeric>& y2, const std::map<std::string, std::string>& keywords)
+{
+    assert(x.size() == y1.size());
+    assert(x.size() == y2.size());
+
+    // using numpy arrays
+    PyObject* xarray = get_array(x);
+    PyObject* y1array = get_array(y1);
+    PyObject* y2array = get_array(y2);
+
+    // construct positional args
+    PyObject* args = PyTuple_New(3);
+    PyTuple_SetItem(args, 0, xarray);
+    PyTuple_SetItem(args, 1, y1array);
+    PyTuple_SetItem(args, 2, y2array);
+
+    // construct keyword args
+    PyObject* kwargs = PyDict_New();
+    for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
+    {
+        PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
+    }
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs);
+
+    Py_DECREF(args);
+    Py_DECREF(kwargs);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template< typename Numeric>
+bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0)
+{
+
+    PyObject* yarray = get_array(y);
+
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
+    PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
+    PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
+
+
+    PyObject* plot_args = PyTuple_New(1);
+
+    PyTuple_SetItem(plot_args, 0, yarray);
+
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
+
+
+    Py_DECREF(plot_args);
+    Py_DECREF(kwargs);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template< typename Numeric>
+bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10, std::string color="b", double alpha=1.0)
+{
+    PyObject* yarray = get_array(y);
+
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
+    PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
+    PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
+    PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
+
+
+    PyObject* plot_args = PyTuple_New(1);
+    PyTuple_SetItem(plot_args, 0, yarray);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
+
+    Py_DECREF(plot_args);
+    Py_DECREF(kwargs);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename NumericX, typename NumericY>
+bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
+{
+    assert(x.size() == y.size());
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(s.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
+
+    Py_DECREF(plot_args);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename NumericX, typename NumericY>
+bool stem(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
+{
+    assert(x.size() == y.size());
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(s.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_CallObject(
+            detail::_interpreter::get().s_python_function_stem, plot_args);
+
+    Py_DECREF(plot_args);
+    if (res)
+        Py_DECREF(res);
+
+    return res;
+}
+
+template<typename NumericX, typename NumericY>
+bool semilogx(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
+{
+    assert(x.size() == y.size());
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(s.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args);
+
+    Py_DECREF(plot_args);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename NumericX, typename NumericY>
+bool semilogy(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
+{
+    assert(x.size() == y.size());
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(s.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args);
+
+    Py_DECREF(plot_args);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename NumericX, typename NumericY>
+bool loglog(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
+{
+    assert(x.size() == y.size());
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(s.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args);
+
+    Py_DECREF(plot_args);
+    if(res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename NumericX, typename NumericY>
+bool errorbar(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::vector<NumericX> &yerr, const std::string &s = "")
+{
+    assert(x.size() == y.size());
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+    PyObject* yerrarray = get_array(yerr);
+
+    PyObject *kwargs = PyDict_New();
+
+    PyDict_SetItemString(kwargs, "yerr", yerrarray);
+
+    PyObject *pystring = PyString_FromString(s.c_str());
+
+    PyObject *plot_args = PyTuple_New(2);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+
+    PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(plot_args);
+
+    if (res)
+        Py_DECREF(res);
+    else
+        throw std::runtime_error("Call to errorbar() failed.");
+
+    return res;
+}
+
+template<typename Numeric>
+bool named_plot(const std::string& name, const std::vector<Numeric>& y, const std::string& format = "")
+{
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
+
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(format.c_str());
+
+    PyObject* plot_args = PyTuple_New(2);
+
+    PyTuple_SetItem(plot_args, 0, yarray);
+    PyTuple_SetItem(plot_args, 1, pystring);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(plot_args);
+    if (res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename Numeric>
+bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
+{
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(format.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(plot_args);
+    if (res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename Numeric>
+bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
+{
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(format.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(plot_args);
+    if (res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename Numeric>
+bool named_semilogy(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
+{
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(format.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(plot_args);
+    if (res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename Numeric>
+bool named_loglog(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
+{
+    PyObject* kwargs = PyDict_New();
+    PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
+
+    PyObject* xarray = get_array(x);
+    PyObject* yarray = get_array(y);
+
+    PyObject* pystring = PyString_FromString(format.c_str());
+
+    PyObject* plot_args = PyTuple_New(3);
+    PyTuple_SetItem(plot_args, 0, xarray);
+    PyTuple_SetItem(plot_args, 1, yarray);
+    PyTuple_SetItem(plot_args, 2, pystring);
+
+    PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(plot_args);
+    if (res) Py_DECREF(res);
+
+    return res;
+}
+
+template<typename Numeric>
+bool plot(const std::vector<Numeric>& y, const std::string& format = "")
+{
+    std::vector<Numeric> x(y.size());
+    for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
+    return plot(x,y,format);
+}
+
+template<typename Numeric>
+bool stem(const std::vector<Numeric>& y, const std::string& format = "")
+{
+    std::vector<Numeric> x(y.size());
+    for (size_t i = 0; i < x.size(); ++i) x.at(i) = i;
+    return stem(x, y, format);
+}
+
+inline void figure()
+{
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple);
+    if(!res) throw std::runtime_error("Call to figure() failed.");
+
+    Py_DECREF(res);
+}
+
+inline void legend()
+{
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
+    if(!res) throw std::runtime_error("Call to legend() failed.");
+
+    Py_DECREF(res);
+}
+
+template<typename Numeric>
+void ylim(Numeric left, Numeric right)
+{
+    PyObject* list = PyList_New(2);
+    PyList_SetItem(list, 0, PyFloat_FromDouble(left));
+    PyList_SetItem(list, 1, PyFloat_FromDouble(right));
+
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, list);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
+    if(!res) throw std::runtime_error("Call to ylim() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+template<typename Numeric>
+void xlim(Numeric left, Numeric right)
+{
+    PyObject* list = PyList_New(2);
+    PyList_SetItem(list, 0, PyFloat_FromDouble(left));
+    PyList_SetItem(list, 1, PyFloat_FromDouble(right));
+
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, list);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
+    if(!res) throw std::runtime_error("Call to xlim() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+
+inline double* xlim()
+{
+    PyObject* args = PyTuple_New(0);
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
+    PyObject* left = PyTuple_GetItem(res,0);
+    PyObject* right = PyTuple_GetItem(res,1);
+
+    double* arr = new double[2];
+    arr[0] = PyFloat_AsDouble(left);
+    arr[1] = PyFloat_AsDouble(right);
+
+    if(!res) throw std::runtime_error("Call to xlim() failed.");
+
+    Py_DECREF(res);
+    return arr;
+}
+
+
+inline double* ylim()
+{
+    PyObject* args = PyTuple_New(0);
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
+    PyObject* left = PyTuple_GetItem(res,0);
+    PyObject* right = PyTuple_GetItem(res,1);
+
+    double* arr = new double[2];
+    arr[0] = PyFloat_AsDouble(left);
+    arr[1] = PyFloat_AsDouble(right);
+
+    if(!res) throw std::runtime_error("Call to ylim() failed.");
+
+    Py_DECREF(res);
+    return arr;
+}
+
+inline void subplot(long nrows, long ncols, long plot_number)
+{
+    // construct positional args
+    PyObject* args = PyTuple_New(3);
+    PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
+    PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
+    PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
+    if(!res) throw std::runtime_error("Call to subplot() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void title(const std::string &titlestr)
+{
+    PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, pytitlestr);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args);
+    if(!res) throw std::runtime_error("Call to title() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void axis(const std::string &axisstr)
+{
+    PyObject* str = PyString_FromString(axisstr.c_str());
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, str);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args);
+    if(!res) throw std::runtime_error("Call to title() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void xlabel(const std::string &str)
+{
+    PyObject* pystr = PyString_FromString(str.c_str());
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, pystr);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args);
+    if(!res) throw std::runtime_error("Call to xlabel() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void ylabel(const std::string &str)
+{
+    PyObject* pystr = PyString_FromString(str.c_str());
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, pystr);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args);
+    if(!res) throw std::runtime_error("Call to ylabel() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void grid(bool flag)
+{
+    PyObject* pyflag = flag ? Py_True : Py_False;
+    Py_INCREF(pyflag);
+
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, pyflag);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args);
+    if(!res) throw std::runtime_error("Call to grid() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void show(const bool block = true)
+{
+    PyObject* res;
+    if(block)
+    {
+        res = PyObject_CallObject(
+                detail::_interpreter::get().s_python_function_show,
+                detail::_interpreter::get().s_python_empty_tuple);
+    }
+    else
+    {
+        PyObject *kwargs = PyDict_New();
+        PyDict_SetItemString(kwargs, "block", Py_False);
+        res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs);
+	Py_DECREF(kwargs);
+    }
+
+
+    if (!res) throw std::runtime_error("Call to show() failed.");
+
+    Py_DECREF(res);
+}
+
+inline void close()
+{
+    PyObject* res = PyObject_CallObject(
+            detail::_interpreter::get().s_python_function_close,
+            detail::_interpreter::get().s_python_empty_tuple);
+
+    if (!res) throw std::runtime_error("Call to close() failed.");
+
+    Py_DECREF(res);
+}
+
+inline void xkcd() {
+    PyObject* res;
+    PyObject *kwargs = PyDict_New();
+
+    res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd,
+            detail::_interpreter::get().s_python_empty_tuple, kwargs);
+
+    Py_DECREF(kwargs);
+
+    if (!res)
+        throw std::runtime_error("Call to show() failed.");
+
+    Py_DECREF(res);
+}
+
+inline void draw()
+{
+    PyObject* res = PyObject_CallObject(
+        detail::_interpreter::get().s_python_function_draw,
+        detail::_interpreter::get().s_python_empty_tuple);
+
+    if (!res) throw std::runtime_error("Call to draw() failed.");
+
+    Py_DECREF(res);
+}
+
+template<typename Numeric>
+inline void pause(Numeric interval)
+{
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval));
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args);
+    if(!res) throw std::runtime_error("Call to pause() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void save(const std::string& filename)
+{
+    PyObject* pyfilename = PyString_FromString(filename.c_str());
+
+    PyObject* args = PyTuple_New(1);
+    PyTuple_SetItem(args, 0, pyfilename);
+
+    PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args);
+    if (!res) throw std::runtime_error("Call to save() failed.");
+
+    Py_DECREF(args);
+    Py_DECREF(res);
+}
+
+inline void clf() {
+    PyObject *res = PyObject_CallObject(
+        detail::_interpreter::get().s_python_function_clf,
+        detail::_interpreter::get().s_python_empty_tuple);
+
+    if (!res) throw std::runtime_error("Call to clf() failed.");
+
+    Py_DECREF(res);
+}
+
+    inline void ion() {
+    PyObject *res = PyObject_CallObject(
+        detail::_interpreter::get().s_python_function_ion,
+        detail::_interpreter::get().s_python_empty_tuple);
+
+    if (!res) throw std::runtime_error("Call to ion() failed.");
+
+    Py_DECREF(res);
+}
+
+// Actually, is there any reason not to call this automatically for every plot?
+inline void tight_layout() {
+    PyObject *res = PyObject_CallObject(
+        detail::_interpreter::get().s_python_function_tight_layout,
+        detail::_interpreter::get().s_python_empty_tuple);
+
+    if (!res) throw std::runtime_error("Call to tight_layout() failed.");
+
+    Py_DECREF(res);
+}
+
+#if __cplusplus > 199711L || _MSC_VER > 1800
+// C++11-exclusive content starts here (variadic plot() and initializer list support)
+
+namespace detail {
+
+template<typename T>
+using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
+
+template<bool obj, typename T>
+struct is_callable_impl;
+
+template<typename T>
+struct is_callable_impl<false, T>
+{
+    typedef is_function<T> type;
+}; // a non-object is callable iff it is a function
+
+template<typename T>
+struct is_callable_impl<true, T>
+{
+    struct Fallback { void operator()(); };
+    struct Derived : T, Fallback { };
+
+    template<typename U, U> struct Check;
+
+    template<typename U>
+    static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
+
+    template<typename U>
+    static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
+
+public:
+    typedef decltype(test<Derived>(nullptr)) type;
+    typedef decltype(&Fallback::operator()) dtype;
+    static constexpr bool value = type::value;
+}; // an object is callable iff it defines operator()
+
+template<typename T>
+struct is_callable
+{
+    // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
+    typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
+};
+
+template<typename IsYDataCallable>
+struct plot_impl { };
+
+template<>
+struct plot_impl<std::false_type>
+{
+    template<typename IterableX, typename IterableY>
+    bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
+    {
+        // 2-phase lookup for distance, begin, end
+        using std::distance;
+        using std::begin;
+        using std::end;
+
+        auto xs = distance(begin(x), end(x));
+        auto ys = distance(begin(y), end(y));
+        assert(xs == ys && "x and y data must have the same number of elements!");
+
+        PyObject* xlist = PyList_New(xs);
+        PyObject* ylist = PyList_New(ys);
+        PyObject* pystring = PyString_FromString(format.c_str());
+
+        auto itx = begin(x), ity = begin(y);
+        for(size_t i = 0; i < xs; ++i) {
+            PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
+            PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
+        }
+
+        PyObject* plot_args = PyTuple_New(3);
+        PyTuple_SetItem(plot_args, 0, xlist);
+        PyTuple_SetItem(plot_args, 1, ylist);
+        PyTuple_SetItem(plot_args, 2, pystring);
+
+        PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
+
+        Py_DECREF(plot_args);
+        if(res) Py_DECREF(res);
+
+        return res;
+    }
+};
+
+template<>
+struct plot_impl<std::true_type>
+{
+    template<typename Iterable, typename Callable>
+    bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
+    {
+        if(begin(ticks) == end(ticks)) return true;
+
+        // We could use additional meta-programming to deduce the correct element type of y,
+        // but all values have to be convertible to double anyways
+        std::vector<double> y;
+        for(auto x : ticks) y.push_back(f(x));
+        return plot_impl<std::false_type>()(ticks,y,format);
+    }
+};
+
+} // end namespace detail
+
+// recursion stop for the above
+template<typename... Args>
+bool plot() { return true; }
+
+template<typename A, typename B, typename... Args>
+bool plot(const A& a, const B& b, const std::string& format, Args... args)
+{
+    return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
+}
+
+/*
+ * This group of plot() functions is needed to support initializer lists, i.e. calling
+ *    plot( {1,2,3,4} )
+ */
+inline bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
+    return plot<double,double>(x,y,format);
+}
+
+inline bool plot(const std::vector<double>& y, const std::string& format = "") {
+    return plot<double>(y,format);
+}
+
+inline bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
+    return plot<double>(x,y,keywords);
+}
+
+#endif
+
+} // end namespace matplotlibcpp