diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d6175a21..00000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: minimal -dist: trusty -services: - - docker -script: - - make -C contrib docker_build diff --git a/CMakeLists.txt b/CMakeLists.txt index bb2decd8..61384d9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,133 +1,74 @@ -cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -project(matplotlib_cpp LANGUAGES CXX) +cmake_minimum_required(VERSION 3.15) +project(Matplotlibrary LANGUAGES CXX) -include(GNUInstallDirs) -set(PACKAGE_NAME matplotlib_cpp) -set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/${PACKAGE_NAME}/cmake) +set(CMAKE_CXX_STANDARD 20) +# Path to Conda environment +# set(CONDA_PREFIX $ENV{CONDA_PREFIX}) -# Library target -add_library(matplotlib_cpp INTERFACE) -target_include_directories(matplotlib_cpp - INTERFACE - $ - $ -) -target_compile_features(matplotlib_cpp INTERFACE - cxx_std_11 -) -# TODO: Use `Development.Embed` component when requiring cmake >= 3.18 -find_package(Python3 COMPONENTS Interpreter Development REQUIRED) -target_link_libraries(matplotlib_cpp INTERFACE - Python3::Python - Python3::Module -) -find_package(Python3 COMPONENTS NumPy) -if(Python3_NumPy_FOUND) - target_link_libraries(matplotlib_cpp INTERFACE - Python3::NumPy - ) +# 1. Try CONDA_PREFIX from environment +if(DEFINED ENV{CONDA_PREFIX} AND NOT "$ENV{CONDA_PREFIX}" STREQUAL "") + set(CONDA_PREFIX $ENV{CONDA_PREFIX}) + message(STATUS "Using Conda environment at: ${CONDA_PREFIX}") else() - target_compile_definitions(matplotlib_cpp INTERFACE WITHOUT_NUMPY) + if(NOT DEFINED CONDA_PREFIX AND "$CONDA_PREFIX" STREQUAL "") + message(WARNING "CONDA_PREFIX is not set. Falling back to system Python.") + + # 2. Try system Python + find_package(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) + + if (Python3_FOUND) + message(STATUS "Found system Python: ${Python3_EXECUTABLE}") + else() + message(FATAL_ERROR "No Python found! Please activate Conda or install python3-dev.") + endif() + endif() endif() -install( - TARGETS matplotlib_cpp - EXPORT install_targets -) - -# Examples -add_executable(minimal examples/minimal.cpp) -target_link_libraries(minimal PRIVATE matplotlib_cpp) -set_target_properties(minimal PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -add_executable(basic examples/basic.cpp) -target_link_libraries(basic PRIVATE matplotlib_cpp) -set_target_properties(basic PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -add_executable(modern examples/modern.cpp) -target_link_libraries(modern PRIVATE matplotlib_cpp) -set_target_properties(modern PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -add_executable(animation examples/animation.cpp) -target_link_libraries(animation PRIVATE matplotlib_cpp) -set_target_properties(animation PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +# main code +add_library(matplotlib + matplotlibcpp.cpp + matplotlibcpp.h +) -add_executable(nonblock examples/nonblock.cpp) -target_link_libraries(nonblock PRIVATE matplotlib_cpp) -set_target_properties(nonblock PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -add_executable(xkcd examples/xkcd.cpp) -target_link_libraries(xkcd PRIVATE matplotlib_cpp) -set_target_properties(xkcd PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +# TODO: you should add this to cmake of your final target ode to clear library paths from Conda for this target, +# NOTE: this is to fix the runtime problem: libstdc++.so.6: version `GLIBCXX_3.4.32' not found +# set_target_properties(matplotlib PROPERTIES +# LINK_FLAGS "-Wl,-rpath,/usr/lib/x86_64-linux-gnu" +# ) -add_executable(bar examples/bar.cpp) -target_link_libraries(bar PRIVATE matplotlib_cpp) -set_target_properties(bar PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -add_executable(fill_inbetween examples/fill_inbetween.cpp) -target_link_libraries(fill_inbetween PRIVATE matplotlib_cpp) -set_target_properties(fill_inbetween PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -add_executable(fill examples/fill.cpp) -target_link_libraries(fill PRIVATE matplotlib_cpp) -set_target_properties(fill PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +if (CONDA_PREFIX) + # Python include + library + set(PYTHON_INCLUDE_DIR "${CONDA_PREFIX}/include/python3.13") + set(PYTHON_LIBRARY "${CONDA_PREFIX}/lib/libpython3.13.so") -add_executable(update examples/update.cpp) -target_link_libraries(update PRIVATE matplotlib_cpp) -set_target_properties(update PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + # Numpy include + # NOTE: (find it via: python -c "import numpy; print(numpy.get_include())") + set(NUMPY_INCLUDE_DIR + "${CONDA_PREFIX}/lib/python3.13/site-packages/numpy/_core/include") + -add_executable(subplot2grid examples/subplot2grid.cpp) -target_link_libraries(subplot2grid PRIVATE matplotlib_cpp) -set_target_properties(subplot2grid PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + # Add include dirs only for this target + target_include_directories(matplotlib PUBLIC + ${CMAKE_SOURCE_DIR} # so your local matplotlibcpp.h is found + ${PYTHON_INCLUDE_DIR} + ${NUMPY_INCLUDE_DIR} + ) -add_executable(lines3d examples/lines3d.cpp) -target_link_libraries(lines3d PRIVATE matplotlib_cpp) -set_target_properties(lines3d PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + # Link against Python shared library + target_link_libraries(matplotlib ${PYTHON_LIBRARY}) -if(Python3_NumPy_FOUND) - add_executable(surface examples/surface.cpp) - target_link_libraries(surface PRIVATE matplotlib_cpp) - set_target_properties(surface PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +else() # no conda - add_executable(colorbar examples/colorbar.cpp) - target_link_libraries(colorbar PRIVATE matplotlib_cpp) - set_target_properties(colorbar PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - add_executable(contour examples/contour.cpp) - target_link_libraries(contour PRIVATE matplotlib_cpp) - set_target_properties(contour PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + target_include_directories(matplotlib PUBLIC + ${CMAKE_SOURCE_DIR} + ${Python3_INCLUDE_DIRS} + ${Python3_NumPy_INCLUDE_DIRS} + ) + target_link_libraries(matplotlib Python3::Python) - add_executable(spy examples/spy.cpp) - target_link_libraries(spy PRIVATE matplotlib_cpp) - set_target_properties(spy PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") endif() - -# Install headers -install(FILES - "${PROJECT_SOURCE_DIR}/matplotlibcpp.h" - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - - -# Install targets file -install(EXPORT install_targets - FILE - ${PACKAGE_NAME}Targets.cmake - NAMESPACE - ${PACKAGE_NAME}:: - DESTINATION - ${INSTALL_CONFIGDIR} -) - - -# Install matplotlib_cppConfig.cmake -include(CMakePackageConfigHelpers) -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PACKAGE_NAME}Config.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}Config.cmake - INSTALL_DESTINATION ${INSTALL_CONFIGDIR} -) -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}Config.cmake - DESTINATION ${INSTALL_CONFIGDIR} -) diff --git a/README.md b/README.md index 0f8479f1..aefd8066 100644 --- a/README.md +++ b/README.md @@ -1,285 +1,65 @@ 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. +This fork is a CMake-ready, ready-to-use adaptation of matplotlib-cpp using custom conda env paths. - - -Usage +Changes from original repo ----- -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 +- Updated deprecated functions +- Ability to include in code and use it in CMake easily +- Ability to easily build against a custom conda env -**Result:** -![Minimal example](./examples/minimal.png) - -A more comprehensive example: -```cpp -#include "matplotlibcpp.h" -#include - -namespace plt = matplotlibcpp; - -int main() -{ - // Prepare data. - int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i -#include "matplotlibcpp.h" - -using namespace std; -namespace plt = matplotlibcpp; - -int main() -{ - // Prepare data. - int n = 5000; // number of data points - vector x(n),y(n); - for(int i=0; i -#include - -namespace plt = matplotlibcpp; - -int main() { - std::vector t(1000); - std::vector 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:** - -![xkcd example](./examples/xkcd.png) - -When working with vector fields, you might be interested in quiver plots: -```cpp -#include "../matplotlibcpp.h" namespace plt = matplotlibcpp; int main() { - // u and v are respectively the x and y components of the arrows we're plotting - std::vector x, y, u, v; - for (int i = -5; i <= 5; i++) { - for (int j = -5; j <= 5; j++) { - x.push_back(i); - u.push_back(-i); - y.push_back(j); - v.push_back(-j); - } - } - - plt::quiver(x, y, u, v); - plt::show(); -} -``` - g++ quiver.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 - -**Result:** - -![quiver example](./examples/quiver.png) - -When working with 3d functions, you might be interested in 3d plots: -```cpp -#include "../matplotlibcpp.h" - -namespace plt = matplotlibcpp; - -int main() -{ - std::vector> x, y, z; - for (double i = -5; i <= 5; i += 0.25) { - std::vector x_row, y_row, z_row; - for (double j = -5; j <= 5; j += 0.25) { - x_row.push_back(i); - y_row.push_back(j); - z_row.push_back(::std::sin(::std::hypot(i, j))); - } - x.push_back(x_row); - y.push_back(y_row); - z.push_back(z_row); - } - - plt::plot_surface(x, y, z); + std::vector x{1, 2, 3, 4, 5}; + std::vector y{1, 4, 9, 16, 25}; + plt::figure_size(1200, 780); + // Plot line from given x and y data. Color is selected automatically. + plt::plot(x, y); + // Set x-axis to interval [0,10] + plt::xlim(0, 10); + // Add graph title + plt::title("Sample figure"); plt::show(); } ``` -**Result:** - -![surface example](./examples/surface.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 define the macro `WITHOUT_NUMPY` before including the header file 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 `libpython` in order to user matplotlib-cpp. Most versions should -work, although python likes to randomly break compatibility from time to time -so some caution is advised when using the bleeding edge. - - -# CMake - -The C++ code is compatible to both python2 and python3. However, the `CMakeLists.txt` -file is currently set up to use python3 by default, so if python2 is required this -has to be changed manually. (a PR that adds a cmake option for this would be highly -welcomed) - -**NOTE**: By design (of python), only a single python interpreter can be created per -process. When using this library, *no other* library that is spawning a python -interpreter internally can be used. - -To compile the code without using cmake, the compiler invocation should look like -this: - - g++ example.cpp -I/usr/include/python2.7 -lpython2.7 - -This can also 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 - -# Vcpkg - -You can download and install matplotlib-cpp using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: - - git clone https://github.com/Microsoft/vcpkg.git - cd vcpkg - ./bootstrap-vcpkg.sh - ./vcpkg integrate install - vcpkg install matplotlib-cpp - -The matplotlib-cpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. - - -# C++11 - -Currently, c++11 is required to build matplotlib-cpp. The last working commit that did -not have this requirement was `717e98e752260245407c5329846f5d62605eff08`. - -Note that support for c++98 was dropped more or less accidentally, so if you have to work -with an ancient compiler and still want to enjoy the latest additional features, I'd -probably merge a PR that restores support. - - - -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, preferably 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. +* 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. diff --git a/cmake/matplotlib_cppConfig.cmake.in b/cmake/matplotlib_cppConfig.cmake.in deleted file mode 100644 index 86d25d09..00000000 --- a/cmake/matplotlib_cppConfig.cmake.in +++ /dev/null @@ -1,10 +0,0 @@ -get_filename_component(matplotlib_cpp_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) - -if(NOT TARGET matplotlib_cpp::matplotlib_cpp) - find_package(Python3 COMPONENTS Interpreter Development REQUIRED) - find_package(Python3 COMPONENTS NumPy) - include("${matplotlib_cpp_CMAKE_DIR}/matplotlib_cppTargets.cmake") - - get_target_property(matplotlib_cpp_INCLUDE_DIRS matplotlib_cpp::matplotlib_cpp INTERFACE_INCLUDE_DIRECTORIES) - -endif() diff --git a/contrib/Dockerfile b/contrib/Dockerfile deleted file mode 100644 index 850466fb..00000000 --- a/contrib/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM debian:10 AS builder -RUN apt-get update \ - && apt-get install --yes --no-install-recommends \ - g++ \ - libpython3-dev \ - make \ - python3 \ - python3-dev \ - python3-numpy - -ADD Makefile matplotlibcpp.h numpy_flags.py /opt/ -ADD examples/*.cpp /opt/examples/ -RUN cd /opt \ - && make PYTHON_BIN=python3 \ - && ls examples/build - -FROM debian:10 -RUN apt-get update \ - && apt-get install --yes --no-install-recommends \ - libpython3-dev \ - python3-matplotlib \ - python3-numpy - -COPY --from=builder /opt/examples/build /opt/ -RUN cd /opt \ - && ls \ - && ./basic diff --git a/contrib/Makefile b/contrib/Makefile deleted file mode 100644 index f659cd94..00000000 --- a/contrib/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: docker_build - -docker_build: - cd .. && \ - docker build . -f contrib/Dockerfile -t matplotlibcpp && \ - cd contrib diff --git a/contrib/README.md b/contrib/README.md deleted file mode 100644 index 0af8515c..00000000 --- a/contrib/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# 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 -Tested on the following environment -* Windows 10 - 64bit -* Anaconda 4.3 (64 bit) -* Python 3.6.0 -* CMake 3.9.4 -* Visual Studio 2017, 2015, 2013 - -### Configuring and Building Samples -1. Edit WinBuild.cmd for your environment(Line:5-7) - if NOT DEFINED MSVC_VERSION set MSVC_VERSION=[Your Visual Studio Version(12, 14, 15)] - if NOT DEFINED CMAKE_CONFIG set CMAKE_CONFIG=Release - if NOT DEFINED PYTHONHOME set PYTHONHOME=[Your Python Path] - -2. Run WinBuild.cmd to build -```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. - -3. Find exe files in examples/build/Release -Note: platforms folder is necessary to make qt works. diff --git a/contrib/WinBuild.cmd b/contrib/WinBuild.cmd deleted file mode 100644 index 9dfd627d..00000000 --- a/contrib/WinBuild.cmd +++ /dev/null @@ -1,61 +0,0 @@ -@echo off -@setlocal EnableDelayedExpansion - -REM ------Set Your Environment------------------------------- -if NOT DEFINED MSVC_VERSION set MSVC_VERSION=15 -if NOT DEFINED CMAKE_CONFIG set CMAKE_CONFIG=Release -if NOT DEFINED PYTHONHOME set PYTHONHOME=C:/Users/%username%/Anaconda3 -REM --------------------------------------------------------- - -set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7" -set VALUE_NAME=15.0 - -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 - ) -) else if "%MSVC_VERSION%"=="15" ( - if "%processor_architecture%" == "AMD64" ( - set CMAKE_GENERATOR=Visual Studio 15 2017 Win64 - ) else ( - set CMAKE_GENERATOR=Visual Studio 15 2017 - ) -) -if "%MSVC_VERSION%"=="15" ( - for /F "usebackq tokens=1,2,*" %%A in (`REG QUERY %KEY_NAME% /v %VALUE_NAME%`) do ( - set batch_file=%%CVC\Auxiliary\Build\vcvarsall.bat - ) -) else ( - 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/matplotlibcpp.cpp b/matplotlibcpp.cpp new file mode 100644 index 00000000..67751d75 --- /dev/null +++ b/matplotlibcpp.cpp @@ -0,0 +1 @@ +#include "matplotlibcpp.h" diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d95d46ad..c054fb99 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -16,2971 +16,3272 @@ #include // std::stod #ifndef WITHOUT_NUMPY -# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -# include +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include -# ifdef WITH_OPENCV -# include -# endif // WITH_OPENCV +#ifdef WITH_OPENCV +#include +#endif // WITH_OPENCV /* * A bunch of constants were removed in OpenCV 4 in favour of enum classes, so * define the ones we need here. */ -# if CV_MAJOR_VERSION > 3 -# define CV_BGR2RGB cv::COLOR_BGR2RGB -# define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA -# endif +#if CV_MAJOR_VERSION > 3 +#define CV_BGR2RGB cv::COLOR_BGR2RGB +#define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA +#endif #endif // WITHOUT_NUMPY #if PY_MAJOR_VERSION >= 3 -# define PyString_FromString PyUnicode_FromString -# define PyInt_FromLong PyLong_FromLong -# define PyString_FromString PyUnicode_FromString +#define PyString_FromString PyUnicode_FromString +#define PyInt_FromLong PyLong_FromLong +#define PyString_FromString PyUnicode_FromString #endif +namespace matplotlibcpp +{ + namespace detail + { -namespace matplotlibcpp { -namespace detail { - -static std::string s_backend; - -struct _interpreter { - PyObject* s_python_function_arrow; - 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_fignum_exists; - PyObject *s_python_function_plot; - PyObject *s_python_function_quiver; - PyObject* s_python_function_contour; - PyObject *s_python_function_semilogx; - PyObject *s_python_function_semilogy; - PyObject *s_python_function_loglog; - PyObject *s_python_function_fill; - PyObject *s_python_function_fill_between; - PyObject *s_python_function_hist; - PyObject *s_python_function_imshow; - PyObject *s_python_function_scatter; - PyObject *s_python_function_boxplot; - PyObject *s_python_function_subplot; - PyObject *s_python_function_subplot2grid; - PyObject *s_python_function_legend; - PyObject *s_python_function_xlim; - PyObject *s_python_function_ion; - PyObject *s_python_function_ginput; - PyObject *s_python_function_ylim; - PyObject *s_python_function_title; - PyObject *s_python_function_axis; - PyObject *s_python_function_axhline; - PyObject *s_python_function_axvline; - PyObject *s_python_function_axvspan; - PyObject *s_python_function_xlabel; - PyObject *s_python_function_ylabel; - PyObject *s_python_function_gca; - PyObject *s_python_function_xticks; - PyObject *s_python_function_yticks; - PyObject* s_python_function_margins; - PyObject *s_python_function_tick_params; - PyObject *s_python_function_grid; - PyObject* s_python_function_cla; - PyObject *s_python_function_clf; - PyObject *s_python_function_errorbar; - PyObject *s_python_function_annotate; - PyObject *s_python_function_tight_layout; - PyObject *s_python_colormap; - PyObject *s_python_empty_tuple; - PyObject *s_python_function_stem; - PyObject *s_python_function_xkcd; - PyObject *s_python_function_text; - PyObject *s_python_function_suptitle; - PyObject *s_python_function_bar; - PyObject *s_python_function_barh; - PyObject *s_python_function_colorbar; - PyObject *s_python_function_subplots_adjust; - PyObject *s_python_function_rcparams; - PyObject *s_python_function_spy; - - /* 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. [1] - Furthermore, many python objects expect that they are destructed in the same thread as they - were constructed. [2] So for advanced usage, a `kill()` function is provided so that library - users can manually ensure that the interpreter is constructed and destroyed within the - same thread. - - 1: http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program - 2: https://github.com/lava/matplotlib-cpp/pull/202#issue-436220256 - */ - - static _interpreter& get() { - return interkeeper(false); - } - - static _interpreter& kill() { - return interkeeper(true); - } - - // Stores the actual singleton object referenced by `get()` and `kill()`. - static _interpreter& interkeeper(bool should_kill) { - static _interpreter ctx; - if (should_kill) - ctx.~_interpreter(); - return ctx; - } - - PyObject* safe_import(PyObject* module, std::string fname) { - PyObject* fn = PyObject_GetAttrString(module, fname.c_str()); - - if (!fn) - throw std::runtime_error(std::string("Couldn't find required function: ") + fname); - - if (!PyFunction_Check(fn)) - throw std::runtime_error(fname + std::string(" is unexpectedly not a PyFunction.")); - - return fn; - } - -private: + static std::string s_backend; + struct _interpreter + { + PyObject *s_python_function_arrow; + 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_fignum_exists; + PyObject *s_python_function_plot; + PyObject *s_python_function_quiver; + PyObject *s_python_function_contour; + PyObject *s_python_function_semilogx; + PyObject *s_python_function_semilogy; + PyObject *s_python_function_loglog; + PyObject *s_python_function_fill; + PyObject *s_python_function_fill_between; + PyObject *s_python_function_hist; + PyObject *s_python_function_imshow; + PyObject *s_python_function_scatter; + PyObject *s_python_function_boxplot; + PyObject *s_python_function_subplot; + PyObject *s_python_function_subplot2grid; + PyObject *s_python_function_legend; + PyObject *s_python_function_xlim; + PyObject *s_python_function_ion; + PyObject *s_python_function_ginput; + PyObject *s_python_function_ylim; + PyObject *s_python_function_title; + PyObject *s_python_function_axis; + PyObject *s_python_function_axhline; + PyObject *s_python_function_axvline; + PyObject *s_python_function_axvspan; + PyObject *s_python_function_xlabel; + PyObject *s_python_function_ylabel; + PyObject *s_python_function_gca; + PyObject *s_python_function_xticks; + PyObject *s_python_function_yticks; + PyObject *s_python_function_margins; + PyObject *s_python_function_tick_params; + PyObject *s_python_function_grid; + PyObject *s_python_function_cla; + PyObject *s_python_function_clf; + PyObject *s_python_function_errorbar; + PyObject *s_python_function_annotate; + PyObject *s_python_function_tight_layout; + PyObject *s_python_colormap; + PyObject *s_python_empty_tuple; + PyObject *s_python_function_stem; + PyObject *s_python_function_xkcd; + PyObject *s_python_function_text; + PyObject *s_python_function_suptitle; + PyObject *s_python_function_bar; + PyObject *s_python_function_barh; + PyObject *s_python_function_colorbar; + PyObject *s_python_function_subplots_adjust; + PyObject *s_python_function_rcparams; + PyObject *s_python_function_spy; + + /* 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. [1] + Furthermore, many python objects expect that they are destructed in the same thread as they + were constructed. [2] So for advanced usage, a `kill()` function is provided so that library + users can manually ensure that the interpreter is constructed and destroyed within the + same thread. + + 1: http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program + 2: https://github.com/lava/matplotlib-cpp/pull/202#issue-436220256 + */ + + static _interpreter &get() + { + return interkeeper(false); + } + + static _interpreter &kill() + { + return interkeeper(true); + } + + // Stores the actual singleton object referenced by `get()` and `kill()`. + static _interpreter &interkeeper(bool should_kill) + { + static _interpreter ctx; + if (should_kill) + ctx.~_interpreter(); + return ctx; + } + + PyObject *safe_import(PyObject *module, std::string fname) + { + PyObject *fn = PyObject_GetAttrString(module, fname.c_str()); + + if (!fn) + throw std::runtime_error(std::string("Couldn't find required function: ") + fname); + + if (!PyFunction_Check(fn)) + throw std::runtime_error(fname + std::string(" is unexpectedly not a PyFunction.")); + + return fn; + } + + private: #ifndef WITHOUT_NUMPY -# if PY_MAJOR_VERSION >= 3 +#if PY_MAJOR_VERSION >= 3 - void *import_numpy() { - import_array(); // initialize C-API - return NULL; - } + void *import_numpy() + { + import_array(); // initialize C-API + return NULL; + } -# else +#else - void import_numpy() { - import_array(); // initialize C-API - } + void import_numpy() + { + import_array(); // initialize C-API + } -# endif +#endif #endif - _interpreter() { + _interpreter() + { - // optional but recommended + // 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(); + // Py_SetProgramName(name); + Py_Initialize(); - wchar_t const *dummy_args[] = {L"Python", NULL}; // const is needed because literals must not be modified - wchar_t const **argv = dummy_args; - int argc = sizeof(dummy_args)/sizeof(dummy_args[0])-1; + wchar_t const *dummy_args[] = {L"Python", NULL}; // const is needed because literals must not be modified + wchar_t const **argv = dummy_args; + int argc = sizeof(dummy_args) / sizeof(dummy_args[0]) - 1; #if PY_MAJOR_VERSION >= 3 - PySys_SetArgv(argc, const_cast(argv)); + // PySys_SetArgv(argc, const_cast(argv)); #else - PySys_SetArgv(argc, (char **)(argv)); + PySys_SetArgv(argc, (char **)(argv)); #endif #ifndef WITHOUT_NUMPY - import_numpy(); // initialize numpy C-API + import_numpy(); // initialize numpy C-API #endif - PyObject* matplotlibname = PyString_FromString("matplotlib"); - PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); - PyObject* cmname = PyString_FromString("matplotlib.cm"); - PyObject* pylabname = PyString_FromString("pylab"); - if (!pyplotname || !pylabname || !matplotlibname || !cmname) { - throw std::runtime_error("couldnt create string"); - } - - PyObject* matplotlib = PyImport_Import(matplotlibname); - - Py_DECREF(matplotlibname); - if (!matplotlib) { - PyErr_Print(); - 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("use"), const_cast("s"), s_backend.c_str()); - } - - - - PyObject* pymod = PyImport_Import(pyplotname); - Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } - - s_python_colormap = PyImport_Import(cmname); - Py_DECREF(cmname); - if (!s_python_colormap) { throw std::runtime_error("Error loading module matplotlib.cm!"); } - - PyObject* pylabmod = PyImport_Import(pylabname); - Py_DECREF(pylabname); - if (!pylabmod) { throw std::runtime_error("Error loading module pylab!"); } - - s_python_function_arrow = safe_import(pymod, "arrow"); - s_python_function_show = safe_import(pymod, "show"); - s_python_function_close = safe_import(pymod, "close"); - s_python_function_draw = safe_import(pymod, "draw"); - s_python_function_pause = safe_import(pymod, "pause"); - s_python_function_figure = safe_import(pymod, "figure"); - s_python_function_fignum_exists = safe_import(pymod, "fignum_exists"); - s_python_function_plot = safe_import(pymod, "plot"); - s_python_function_quiver = safe_import(pymod, "quiver"); - s_python_function_contour = safe_import(pymod, "contour"); - s_python_function_semilogx = safe_import(pymod, "semilogx"); - s_python_function_semilogy = safe_import(pymod, "semilogy"); - s_python_function_loglog = safe_import(pymod, "loglog"); - s_python_function_fill = safe_import(pymod, "fill"); - s_python_function_fill_between = safe_import(pymod, "fill_between"); - s_python_function_hist = safe_import(pymod,"hist"); - s_python_function_scatter = safe_import(pymod,"scatter"); - s_python_function_boxplot = safe_import(pymod,"boxplot"); - s_python_function_subplot = safe_import(pymod, "subplot"); - s_python_function_subplot2grid = safe_import(pymod, "subplot2grid"); - s_python_function_legend = safe_import(pymod, "legend"); - s_python_function_xlim = safe_import(pymod, "xlim"); - s_python_function_ylim = safe_import(pymod, "ylim"); - s_python_function_title = safe_import(pymod, "title"); - s_python_function_axis = safe_import(pymod, "axis"); - s_python_function_axhline = safe_import(pymod, "axhline"); - s_python_function_axvline = safe_import(pymod, "axvline"); - s_python_function_axvspan = safe_import(pymod, "axvspan"); - s_python_function_xlabel = safe_import(pymod, "xlabel"); - s_python_function_ylabel = safe_import(pymod, "ylabel"); - s_python_function_gca = safe_import(pymod, "gca"); - s_python_function_xticks = safe_import(pymod, "xticks"); - s_python_function_yticks = safe_import(pymod, "yticks"); - s_python_function_margins = safe_import(pymod, "margins"); - s_python_function_tick_params = safe_import(pymod, "tick_params"); - s_python_function_grid = safe_import(pymod, "grid"); - s_python_function_ion = safe_import(pymod, "ion"); - s_python_function_ginput = safe_import(pymod, "ginput"); - s_python_function_save = safe_import(pylabmod, "savefig"); - s_python_function_annotate = safe_import(pymod,"annotate"); - s_python_function_cla = safe_import(pymod, "cla"); - s_python_function_clf = safe_import(pymod, "clf"); - s_python_function_errorbar = safe_import(pymod, "errorbar"); - s_python_function_tight_layout = safe_import(pymod, "tight_layout"); - s_python_function_stem = safe_import(pymod, "stem"); - s_python_function_xkcd = safe_import(pymod, "xkcd"); - s_python_function_text = safe_import(pymod, "text"); - s_python_function_suptitle = safe_import(pymod, "suptitle"); - s_python_function_bar = safe_import(pymod,"bar"); - s_python_function_barh = safe_import(pymod, "barh"); - s_python_function_colorbar = PyObject_GetAttrString(pymod, "colorbar"); - s_python_function_subplots_adjust = safe_import(pymod,"subplots_adjust"); - s_python_function_rcparams = PyObject_GetAttrString(pymod, "rcParams"); - s_python_function_spy = PyObject_GetAttrString(pymod, "spy"); + PyObject *matplotlibname = PyString_FromString("matplotlib"); + PyObject *pyplotname = PyString_FromString("matplotlib.pyplot"); + PyObject *cmname = PyString_FromString("matplotlib.cm"); + PyObject *pylabname = PyString_FromString("pylab"); + if (!pyplotname || !pylabname || !matplotlibname || !cmname) + { + throw std::runtime_error("couldnt create string"); + } + + PyObject *matplotlib = PyImport_Import(matplotlibname); + + Py_DECREF(matplotlibname); + if (!matplotlib) + { + PyErr_Print(); + 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("use"), const_cast("s"), s_backend.c_str()); + } + + PyObject *pymod = PyImport_Import(pyplotname); + Py_DECREF(pyplotname); + if (!pymod) + { + throw std::runtime_error("Error loading module matplotlib.pyplot!"); + } + + s_python_colormap = PyImport_Import(cmname); + Py_DECREF(cmname); + if (!s_python_colormap) + { + throw std::runtime_error("Error loading module matplotlib.cm!"); + } + + PyObject *pylabmod = PyImport_Import(pylabname); + Py_DECREF(pylabname); + if (!pylabmod) + { + throw std::runtime_error("Error loading module pylab!"); + } + + s_python_function_arrow = safe_import(pymod, "arrow"); + s_python_function_show = safe_import(pymod, "show"); + s_python_function_close = safe_import(pymod, "close"); + s_python_function_draw = safe_import(pymod, "draw"); + s_python_function_pause = safe_import(pymod, "pause"); + s_python_function_figure = safe_import(pymod, "figure"); + s_python_function_fignum_exists = safe_import(pymod, "fignum_exists"); + s_python_function_plot = safe_import(pymod, "plot"); + s_python_function_quiver = safe_import(pymod, "quiver"); + s_python_function_contour = safe_import(pymod, "contour"); + s_python_function_semilogx = safe_import(pymod, "semilogx"); + s_python_function_semilogy = safe_import(pymod, "semilogy"); + s_python_function_loglog = safe_import(pymod, "loglog"); + s_python_function_fill = safe_import(pymod, "fill"); + s_python_function_fill_between = safe_import(pymod, "fill_between"); + s_python_function_hist = safe_import(pymod, "hist"); + s_python_function_scatter = safe_import(pymod, "scatter"); + s_python_function_boxplot = safe_import(pymod, "boxplot"); + s_python_function_subplot = safe_import(pymod, "subplot"); + s_python_function_subplot2grid = safe_import(pymod, "subplot2grid"); + s_python_function_legend = safe_import(pymod, "legend"); + s_python_function_xlim = safe_import(pymod, "xlim"); + s_python_function_ylim = safe_import(pymod, "ylim"); + s_python_function_title = safe_import(pymod, "title"); + s_python_function_axis = safe_import(pymod, "axis"); + s_python_function_axhline = safe_import(pymod, "axhline"); + s_python_function_axvline = safe_import(pymod, "axvline"); + s_python_function_axvspan = safe_import(pymod, "axvspan"); + s_python_function_xlabel = safe_import(pymod, "xlabel"); + s_python_function_ylabel = safe_import(pymod, "ylabel"); + s_python_function_gca = safe_import(pymod, "gca"); + s_python_function_xticks = safe_import(pymod, "xticks"); + s_python_function_yticks = safe_import(pymod, "yticks"); + s_python_function_margins = safe_import(pymod, "margins"); + s_python_function_tick_params = safe_import(pymod, "tick_params"); + s_python_function_grid = safe_import(pymod, "grid"); + s_python_function_ion = safe_import(pymod, "ion"); + s_python_function_ginput = safe_import(pymod, "ginput"); + s_python_function_save = safe_import(pylabmod, "savefig"); + s_python_function_annotate = safe_import(pymod, "annotate"); + s_python_function_cla = safe_import(pymod, "cla"); + s_python_function_clf = safe_import(pymod, "clf"); + s_python_function_errorbar = safe_import(pymod, "errorbar"); + s_python_function_tight_layout = safe_import(pymod, "tight_layout"); + s_python_function_stem = safe_import(pymod, "stem"); + s_python_function_xkcd = safe_import(pymod, "xkcd"); + s_python_function_text = safe_import(pymod, "text"); + s_python_function_suptitle = safe_import(pymod, "suptitle"); + s_python_function_bar = safe_import(pymod, "bar"); + s_python_function_barh = safe_import(pymod, "barh"); + s_python_function_colorbar = PyObject_GetAttrString(pymod, "colorbar"); + s_python_function_subplots_adjust = safe_import(pymod, "subplots_adjust"); + s_python_function_rcparams = PyObject_GetAttrString(pymod, "rcParams"); + s_python_function_spy = PyObject_GetAttrString(pymod, "spy"); #ifndef WITHOUT_NUMPY - s_python_function_imshow = safe_import(pymod, "imshow"); + s_python_function_imshow = safe_import(pymod, "imshow"); #endif - s_python_empty_tuple = PyTuple_New(0); - } - - ~_interpreter() { - Py_Finalize(); + s_python_empty_tuple = PyTuple_New(0); + } + + ~_interpreter() + { + Py_Finalize(); + } + }; + + } // end namespace detail + + /// Select the backend + /// + /// **NOTE:** This must be called before the first plot command to have + /// any effect. + /// + /// Mainly useful to select the non-interactive 'Agg' backend when running + /// matplotlibcpp in headless mode, for example on a machine with no display. + /// + /// See also: https://matplotlib.org/2.0.2/api/matplotlib_configuration_api.html#matplotlib.use + inline void backend(const std::string &name) + { + detail::s_backend = name; } -}; - -} // end namespace detail - -/// Select the backend -/// -/// **NOTE:** This must be called before the first plot command to have -/// any effect. -/// -/// Mainly useful to select the non-interactive 'Agg' backend when running -/// matplotlibcpp in headless mode, for example on a machine with no display. -/// -/// See also: https://matplotlib.org/2.0.2/api/matplotlib_configuration_api.html#matplotlib.use -inline void backend(const std::string& name) -{ - detail::s_backend = name; -} -inline bool annotate(std::string annotation, double x, double y) -{ - detail::_interpreter::get(); + inline bool annotate(std::string annotation, double x, double y) + { + detail::_interpreter::get(); - PyObject * xy = PyTuple_New(2); - PyObject * str = PyString_FromString(annotation.c_str()); + 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)); + PyTuple_SetItem(xy, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(xy, 1, PyFloat_FromDouble(y)); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "xy", xy); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "xy", xy); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, str); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) + Py_DECREF(res); - return res; -} + return res; + } -namespace detail { + namespace detail + { #ifndef WITHOUT_NUMPY -// Type selector for numpy array conversion -template struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default -template <> struct select_npy_type { const static NPY_TYPES type = NPY_DOUBLE; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_FLOAT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_BOOL; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT8; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_SHORT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT8; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_USHORT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_ULONG; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; - -// Sanity checks; comment them out or change the numpy type below if you're compiling on -// a platform where they don't apply -static_assert(sizeof(long long) == 8); -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; -static_assert(sizeof(unsigned long long) == 8); -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; - -template -PyObject* get_array(const std::vector& v) -{ - npy_intp vsize = v.size(); - NPY_TYPES type = select_npy_type::type; - if (type == NPY_NOTYPE) { - size_t memsize = v.size()*sizeof(double); - double* dp = static_cast(::malloc(memsize)); - for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); - return varray; - } - - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); - return varray; -} + // Type selector for numpy array conversion + template + struct select_npy_type + { + const static NPY_TYPES type = NPY_NOTYPE; + }; // Default + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_DOUBLE; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_FLOAT; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_BOOL; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_INT8; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_SHORT; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_INT; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_INT64; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_UINT8; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_USHORT; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_ULONG; + }; + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_UINT64; + }; + + // Sanity checks; comment them out or change the numpy type below if you're compiling on + // a platform where they don't apply + static_assert(sizeof(long long) == 8); + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_INT64; + }; + static_assert(sizeof(unsigned long long) == 8); + template <> + struct select_npy_type + { + const static NPY_TYPES type = NPY_UINT64; + }; + template + PyObject *get_array(const std::vector &v) + { + npy_intp vsize = v.size(); + NPY_TYPES type = select_npy_type::type; + if (type == NPY_NOTYPE) + { + size_t memsize = v.size() * sizeof(double); + double *dp = static_cast(::malloc(memsize)); + for (size_t i = 0; i < v.size(); ++i) + dp[i] = v[i]; + PyObject *varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, dp); + PyArray_UpdateFlags(reinterpret_cast(varray), NPY_ARRAY_OWNDATA); + return varray; + } + + PyObject *varray = PyArray_SimpleNewFromData(1, &vsize, type, (void *)(v.data())); + return varray; + } -template -PyObject* get_2darray(const std::vector<::std::vector>& v) -{ - if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); + template + PyObject *get_2darray(const std::vector<::std::vector> &v) + { + if (v.size() < 1) + throw std::runtime_error("get_2d_array v too small"); - npy_intp vsize[2] = {static_cast(v.size()), - static_cast(v[0].size())}; + npy_intp vsize[2] = {static_cast(v.size()), + static_cast(v[0].size())}; - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); + PyArrayObject *varray = + (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - double *vd_begin = static_cast(PyArray_DATA(varray)); + double *vd_begin = static_cast(PyArray_DATA(varray)); - for (const ::std::vector &v_row : v) { - if (v_row.size() != static_cast(vsize[1])) - throw std::runtime_error("Missmatched array size"); - std::copy(v_row.begin(), v_row.end(), vd_begin); - vd_begin += vsize[1]; - } + for (const ::std::vector &v_row : v) + { + if (v_row.size() != static_cast(vsize[1])) + throw std::runtime_error("Missmatched array size"); + std::copy(v_row.begin(), v_row.end(), vd_begin); + vd_begin += vsize[1]; + } - return reinterpret_cast(varray); -} + return reinterpret_cast(varray); + } #else // fallback if we don't have numpy: copy every element of the given vector -template -PyObject* get_array(const std::vector& 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; -} + template + PyObject *get_array(const std::vector &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 -// sometimes, for labels and such, we need string arrays -inline PyObject * get_array(const std::vector& strings) -{ - PyObject* list = PyList_New(strings.size()); - for (std::size_t i = 0; i < strings.size(); ++i) { - PyList_SetItem(list, i, PyString_FromString(strings[i].c_str())); - } - return list; -} - -// not all matplotlib need 2d arrays, some prefer lists of lists -template -PyObject* get_listlist(const std::vector>& ll) -{ - PyObject* listlist = PyList_New(ll.size()); - for (std::size_t i = 0; i < ll.size(); ++i) { - PyList_SetItem(listlist, i, get_array(ll[i])); - } - return listlist; -} - -} // namespace detail - -/// Plot a line through the given x and y data points.. -/// -/// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html -template -bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); + // sometimes, for labels and such, we need string arrays + inline PyObject *get_array(const std::vector &strings) + { + PyObject *list = PyList_New(strings.size()); + for (std::size_t i = 0; i < strings.size(); ++i) + { + PyList_SetItem(list, i, PyString_FromString(strings[i].c_str())); + } + return list; + } - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + // not all matplotlib need 2d arrays, some prefer lists of lists + template + PyObject *get_listlist(const std::vector> &ll) + { + PyObject *listlist = PyList_New(ll.size()); + for (std::size_t i = 0; i < ll.size(); ++i) + { + PyList_SetItem(listlist, i, get_array(ll[i])); + } + return listlist; + } - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); + } // namespace detail - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + /// Plot a line through the given x and y data points.. + /// + /// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html + template + bool plot(const std::vector &x, const std::vector &y, const std::map &keywords) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } + assert(x.size() == y.size()); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); + detail::_interpreter::get(); - Py_DECREF(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - return res; -} + // construct positional args + PyObject *args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); -// TODO - it should be possible to make this work by implementing -// a non-numpy alternative for `detail::get_2darray()`. -#ifndef WITHOUT_NUMPY -template -void plot_surface(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - const std::map &keywords = - std::map(), - const long fig_number=0) -{ - detail::_interpreter::get(); - - // We lazily load the modules here the first time this function is called - // because I'm not sure that we can assume "matplotlib installed" implies - // "mpl_toolkits installed" on all platforms, and we don't want to require - // it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); - PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); - - PyObject *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); - - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - if (it->first == "linewidth" || it->first == "alpha") { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); - } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - } - - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject( - detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface"); - if (!plot_surface) throw std::runtime_error("No surface"); - Py_INCREF(plot_surface); - PyObject *res = PyObject_Call(plot_surface, args, kwargs); - if (!res) throw std::runtime_error("failed surface"); - Py_DECREF(plot_surface); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -void contour(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - PyObject *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); - - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - - for (std::map::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_contour, args, kwargs); - if (!res) - throw std::runtime_error("failed contour"); - - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -void spy(const std::vector<::std::vector> &x, - const double markersize = -1, // -1 for default matplotlib size - const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - PyObject *xarray = detail::get_2darray(x); - - PyObject *kwargs = PyDict_New(); - if (markersize != -1) { - PyDict_SetItemString(kwargs, "markersize", PyFloat_FromDouble(markersize)); - } - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject *plot_args = PyTuple_New(1); - PyTuple_SetItem(plot_args, 0, xarray); - - PyObject *res = PyObject_Call( - detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} -#endif // WITHOUT_NUMPY + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } -template -void plot3(const std::vector &x, - const std::vector &y, - const std::vector &z, - const std::map &keywords = - std::map(), - const long fig_number=0) -{ - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - PyObject *zarray = detail::get_array(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot3 = PyObject_GetAttrString(axis, "plot"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject *res = PyObject_Call(plot3, args, kwargs); - if (!res) throw std::runtime_error("Failed 3D line plot"); - Py_DECREF(plot3); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -bool stem(const std::vector &x, const std::vector &y, const std::map& keywords) -{ - assert(x.size() == y.size()); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - detail::_interpreter::get(); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + return res; + } - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); +// TODO - it should be possible to make this work by implementing +// a non-numpy alternative for `detail::get_2darray()`. +#ifndef WITHOUT_NUMPY + template + void plot_surface(const std::vector<::std::vector> &x, + const std::vector<::std::vector> &y, + const std::vector<::std::vector> &z, + const std::map &keywords = + std::map(), + const long fig_number = 0) + { + detail::_interpreter::get(); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } + // We lazily load the modules here the first time this function is called + // because I'm not sure that we can assume "matplotlib installed" implies + // "mpl_toolkits installed" on all platforms, and we don't want to require + // it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) + { + detail::_interpreter::get(); + + PyObject *mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject *axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) + { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) + { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) + { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, kwargs); + assert(x.size() == y.size()); + assert(y.size() == z.size()); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + // using numpy arrays + PyObject *xarray = detail::get_2darray(x); + PyObject *yarray = detail::get_2darray(y); + PyObject *zarray = detail::get_2darray(z); - return res; -} + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -{ - assert(x.size() == y.size()); + // Build up the kw args. + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); + PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); - detail::_interpreter::get(); + PyObject *python_colormap_coolwarm = PyObject_GetAttrString( + detail::_interpreter::get().s_python_colormap, "coolwarm"); - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) + { + if (it->first == "linewidth" || it->first == "alpha") + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyFloat_FromDouble(std::stod(it->second))); + } + else + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } + } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + PyObject *fig_args = PyTuple_New(1); + PyObject *fig = nullptr; + PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); + PyObject *fig_exists = + PyObject_CallObject( + detail::_interpreter::get().s_python_function_fignum_exists, fig_args); + if (!PyObject_IsTrue(fig_exists)) + { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + } + else + { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + fig_args); + } + Py_DECREF(fig_exists); + if (!fig) + throw std::runtime_error("Call to figure() failed."); + + PyObject *gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject *gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) + throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject *axis = PyObject_Call( + gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) + throw std::runtime_error("No axis"); + Py_INCREF(axis); + + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface"); + if (!plot_surface) + throw std::runtime_error("No surface"); + Py_INCREF(plot_surface); + PyObject *res = PyObject_Call(plot_surface, args, kwargs); + if (!res) + throw std::runtime_error("failed surface"); + Py_DECREF(plot_surface); + + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs); + template + void contour(const std::vector<::std::vector> &x, + const std::vector<::std::vector> &y, + const std::vector<::std::vector> &z, + const std::map &keywords = {}) + { + detail::_interpreter::get(); + + // using numpy arrays + PyObject *xarray = detail::get_2darray(x); + PyObject *yarray = detail::get_2darray(y); + PyObject *zarray = detail::get_2darray(z); - Py_DECREF(args); - Py_DECREF(kwargs); + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); - if (res) Py_DECREF(res); + // Build up the kw args. + PyObject *kwargs = PyDict_New(); - return res; -} + PyObject *python_colormap_coolwarm = PyObject_GetAttrString( + detail::_interpreter::get().s_python_colormap, "coolwarm"); -template< typename Numeric > -bool fill_between(const std::vector& x, const std::vector& y1, const std::vector& y2, const std::map& keywords) -{ - assert(x.size() == y1.size()); - assert(x.size() == y2.size()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* y1array = detail::get_array(y1); - PyObject* y2array = detail::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::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 -bool arrow(Numeric x, Numeric y, Numeric end_x, Numeric end_y, const std::string& fc = "r", - const std::string ec = "k", Numeric head_length = 0.25, Numeric head_width = 0.1625) { - PyObject* obj_x = PyFloat_FromDouble(x); - PyObject* obj_y = PyFloat_FromDouble(y); - PyObject* obj_end_x = PyFloat_FromDouble(end_x); - PyObject* obj_end_y = PyFloat_FromDouble(end_y); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "fc", PyString_FromString(fc.c_str())); - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "head_width", PyFloat_FromDouble(head_width)); - PyDict_SetItemString(kwargs, "head_length", PyFloat_FromDouble(head_length)); - - PyObject* plot_args = PyTuple_New(4); - PyTuple_SetItem(plot_args, 0, obj_x); - PyTuple_SetItem(plot_args, 1, obj_y); - PyTuple_SetItem(plot_args, 2, obj_end_x); - PyTuple_SetItem(plot_args, 3, obj_end_y); - - PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } - return res; -} + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs); + if (!res) + throw std::runtime_error("failed contour"); -template< typename Numeric> -bool hist(const std::vector& y, long bins=10,std::string color="b", - double alpha=1.0, bool cumulative=false) -{ - detail::_interpreter::get(); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + } - PyObject* yarray = detail::get_array(y); + template + void spy(const std::vector<::std::vector> &x, + const double markersize = -1, // -1 for default matplotlib size + const std::map &keywords = {}) + { + detail::_interpreter::get(); - 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)); - PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); + PyObject *xarray = detail::get_2darray(x); - PyObject* plot_args = PyTuple_New(1); + PyObject *kwargs = PyDict_New(); + if (markersize != -1) + { + PyDict_SetItemString(kwargs, "markersize", PyFloat_FromDouble(markersize)); + } + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } - PyTuple_SetItem(plot_args, 0, yarray); + PyObject *plot_args = PyTuple_New(1); + PyTuple_SetItem(plot_args, 0, xarray); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); - 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); + } +#endif // WITHOUT_NUMPY + template + void plot3(const std::vector &x, + const std::vector &y, + const std::vector &z, + const std::map &keywords = + std::map(), + const long fig_number = 0) + { + detail::_interpreter::get(); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + // Same as with plot_surface: We lazily load the modules here the first time + // this function is called because I'm not sure that we can assume "matplotlib + // installed" implies "mpl_toolkits installed" on all platforms, and we don't + // want to require it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) + { + detail::_interpreter::get(); + + PyObject *mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject *axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) + { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) + { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) + { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - return res; -} + assert(x.size() == y.size()); + assert(y.size() == z.size()); -#ifndef WITHOUT_NUMPY -namespace detail { + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *zarray = detail::get_array(z); -inline void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map &keywords, PyObject** out) -{ - assert(type == NPY_UINT8 || type == NPY_FLOAT); - assert(colors == 1 || colors == 3 || colors == 4); + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); - detail::_interpreter::get(); + // Build up the kw args. + PyObject *kwargs = PyDict_New(); - // construct args - npy_intp dims[3] = { rows, columns, colors }; - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr)); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + PyObject *fig_args = PyTuple_New(1); + PyObject *fig = nullptr; + PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); + PyObject *fig_exists = + PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); + if (!PyObject_IsTrue(fig_exists)) + { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + } + else + { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + fig_args); + } + if (!fig) + throw std::runtime_error("Call to figure() failed."); + + PyObject *gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject *gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) + throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject *axis = PyObject_Call( + gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) + throw std::runtime_error("No axis"); + Py_INCREF(axis); + + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + PyObject *plot3 = PyObject_GetAttrString(axis, "plot"); + if (!plot3) + throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject *res = PyObject_Call(plot3, args, kwargs); + if (!res) + throw std::runtime_error("Failed 3D line plot"); + Py_DECREF(plot3); + + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); } - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) - throw std::runtime_error("Call to imshow() failed"); - if (out) - *out = res; - else - Py_DECREF(res); -} - -} // namespace detail + template + bool stem(const std::vector &x, const std::vector &y, const std::map &keywords) + { + assert(x.size() == y.size()); -inline void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject** out = nullptr) -{ - detail::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords, out); -} + detail::_interpreter::get(); -inline void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject** out = nullptr) -{ - detail::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords, out); -} + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); -#ifdef WITH_OPENCV -void imshow(const cv::Mat &image, const std::map &keywords = {}) -{ - // Convert underlying type of matrix, if needed - cv::Mat image2; - NPY_TYPES npy_type = NPY_UINT8; - switch (image.type() & CV_MAT_DEPTH_MASK) { - case CV_8U: - image2 = image; - break; - case CV_32F: - image2 = image; - npy_type = NPY_FLOAT; - break; - default: - image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels())); - } - - // If color image, convert from BGR to RGB - switch (image2.channels()) { - case 3: - cv::cvtColor(image2, image2, CV_BGR2RGB); - break; - case 4: - cv::cvtColor(image2, image2, CV_BGRA2RGBA); - } - - detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords); -} -#endif // WITH_OPENCV -#endif // WITHOUT_NUMPY + // construct positional args + PyObject *args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); -template -bool scatter(const std::vector& x, - const std::vector& y, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}) -{ - detail::_interpreter::get(); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = + keywords.begin(); + it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } - assert(x.size() == y.size()); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_stem, args, kwargs); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + return res; } - 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_scatter, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -template - bool scatter_colored(const std::vector& x, - const std::vector& y, - const std::vector& colors, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}) + template + bool fill(const std::vector &x, const std::vector &y, const std::map &keywords) { - detail::_interpreter::get(); - assert(x.size() == y.size()); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* colors_array = detail::get_array(colors); + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - PyDict_SetItemString(kwargs, "c", colors_array); + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - for (const auto& it : keywords) + // 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 (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.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_fill, args, kwargs); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); - - Py_DECREF(plot_args); + Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; - } - - -template -bool scatter(const std::vector& x, - const std::vector& y, - const std::vector& z, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}, - const long fig_number=0) { - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - PyObject *zarray = detail::get_array(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot3 = PyObject_GetAttrString(axis, "scatter"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject *res = PyObject_Call(plot3, args, kwargs); - if (!res) throw std::runtime_error("Failed 3D line plot"); - Py_DECREF(plot3); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(fig); - if (res) Py_DECREF(res); - return res; - -} - -template -bool boxplot(const std::vector>& data, - const std::vector& labels = {}, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* listlist = detail::get_listlist(data); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, listlist); - PyObject* kwargs = PyDict_New(); + if (res) + Py_DECREF(res); - // kwargs needs the labels, if there are (the correct number of) labels - if (!labels.empty() && labels.size() == data.size()) { - PyDict_SetItemString(kwargs, "labels", detail::get_array(labels)); + return res; } - // take care of the remaining keywords - for (const auto& it : keywords) + template + bool fill_between(const std::vector &x, const std::vector &y1, const std::vector &y2, const std::map &keywords) { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } + assert(x.size() == y1.size()); + assert(x.size() == y2.size()); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + detail::_interpreter::get(); - Py_DECREF(args); - Py_DECREF(kwargs); + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *y1array = detail::get_array(y1); + PyObject *y2array = detail::get_array(y2); - if(res) Py_DECREF(res); + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, y1array); + PyTuple_SetItem(args, 2, y2array); - return res; -} + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } -template -bool boxplot(const std::vector& data, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs); - PyObject* vector = detail::get_array(data); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, vector); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - PyObject* kwargs = PyDict_New(); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + return res; } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); + template + bool arrow(Numeric x, Numeric y, Numeric end_x, Numeric end_y, const std::string &fc = "r", + const std::string ec = "k", Numeric head_length = 0.25, Numeric head_width = 0.1625) + { + PyObject *obj_x = PyFloat_FromDouble(x); + PyObject *obj_y = PyFloat_FromDouble(y); + PyObject *obj_end_x = PyFloat_FromDouble(end_x); + PyObject *obj_end_y = PyFloat_FromDouble(end_y); - return res; -} + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "fc", PyString_FromString(fc.c_str())); + PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); + PyDict_SetItemString(kwargs, "head_width", PyFloat_FromDouble(head_width)); + PyDict_SetItemString(kwargs, "head_length", PyFloat_FromDouble(head_length)); + + PyObject *plot_args = PyTuple_New(4); + PyTuple_SetItem(plot_args, 0, obj_x); + PyTuple_SetItem(plot_args, 1, obj_y); + PyTuple_SetItem(plot_args, 2, obj_end_x); + PyTuple_SetItem(plot_args, 3, obj_end_y); + + PyObject *res = + PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); -template -bool bar(const std::vector & x, - const std::vector & y, - std::string ec = "black", - std::string ls = "-", - double lw = 1.0, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - PyObject * xarray = detail::get_array(x); - PyObject * yarray = detail::get_array(y); + return res; + } - PyObject * kwargs = PyDict_New(); + template + bool hist(const std::vector &y, long bins = 10, std::string color = "b", + double alpha = 1.0, bool cumulative = false) + { + detail::_interpreter::get(); - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); - PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); + PyObject *yarray = detail::get_array(y); - for (std::map::const_iterator it = - keywords.begin(); - it != keywords.end(); - ++it) { - PyDict_SetItemString( - kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } + 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)); + PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); - PyObject * plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + PyObject *plot_args = PyTuple_New(1); - PyObject * res = PyObject_Call( - detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); + PyTuple_SetItem(plot_args, 0, yarray); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); - return res; -} + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); -template -bool bar(const std::vector & y, - std::string ec = "black", - std::string ls = "-", - double lw = 1.0, - const std::map & keywords = {}) -{ - using T = typename std::remove_reference::type::value_type; + return res; + } - detail::_interpreter::get(); +#ifndef WITHOUT_NUMPY + namespace detail + { - std::vector x; - for (std::size_t i = 0; i < y.size(); i++) { x.push_back(i); } + inline void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map &keywords, PyObject **out) + { + assert(type == NPY_UINT8 || type == NPY_FLOAT); + assert(colors == 1 || colors == 3 || colors == 4); + + detail::_interpreter::get(); + + // construct args + npy_intp dims[3] = {rows, columns, colors}; + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr)); + + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::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_imshow, args, kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to imshow() failed"); + if (out) + *out = res; + else + Py_DECREF(res); + } - return bar(x, y, ec, ls, lw, keywords); -} + } // namespace detail + inline void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject **out = nullptr) + { + detail::imshow((void *)ptr, NPY_UINT8, rows, columns, colors, keywords, out); + } -template -bool barh(const std::vector &x, const std::vector &y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map &keywords = { }) { - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); + inline void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject **out = nullptr) + { + detail::imshow((void *)ptr, NPY_FLOAT, rows, columns, colors, keywords, out); + } - PyObject *kwargs = PyDict_New(); +#ifdef WITH_OPENCV + void imshow(const cv::Mat &image, const std::map &keywords = {}) + { + // Convert underlying type of matrix, if needed + cv::Mat image2; + NPY_TYPES npy_type = NPY_UINT8; + switch (image.type() & CV_MAT_DEPTH_MASK) + { + case CV_8U: + image2 = image; + break; + case CV_32F: + image2 = image; + npy_type = NPY_FLOAT; + break; + default: + image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels())); + } - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); - PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); + // If color image, convert from BGR to RGB + switch (image2.channels()) + { + case 3: + cv::cvtColor(image2, image2, CV_BGR2RGB); + break; + case 4: + cv::cvtColor(image2, image2, CV_BGRA2RGBA); + } - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords); } +#endif // WITH_OPENCV +#endif // WITHOUT_NUMPY - PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + template + bool scatter(const std::vector &x, + const std::vector &y, + const double s = 1.0, // The marker size in points**2 + const std::map &keywords = {}) + { + detail::_interpreter::get(); - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_barh, plot_args, kwargs); + assert(x.size() == y.size()); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - return res; -} + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); + for (const auto &it : keywords) + { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); -inline bool subplots_adjust(const std::map& keywords = {}) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(it->second)); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; } + template + bool scatter_colored(const std::vector &x, + const std::vector &y, + const std::vector &colors, + const double s = 1.0, // The marker size in points**2 + const std::map &keywords = {}) + { + detail::_interpreter::get(); - PyObject* plot_args = PyTuple_New(0); + assert(x.size() == y.size()); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *colors_array = detail::get_array(colors); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); + PyDict_SetItemString(kwargs, "c", colors_array); - return res; -} + for (const auto &it : keywords) + { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } -template< typename Numeric> -bool named_hist(std::string label,const std::vector& y, long bins=10, std::string color="b", double alpha=1.0) -{ - detail::_interpreter::get(); + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - PyObject* yarray = detail::get_array(y); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); - 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)); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + return res; + } - PyObject* plot_args = PyTuple_New(1); - PyTuple_SetItem(plot_args, 0, yarray); + template + bool scatter(const std::vector &x, + const std::vector &y, + const std::vector &z, + const double s = 1.0, // The marker size in points**2 + const std::map &keywords = {}, + const long fig_number = 0) + { + detail::_interpreter::get(); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); + // Same as with plot_surface: We lazily load the modules here the first time + // this function is called because I'm not sure that we can assume "matplotlib + // installed" implies "mpl_toolkits installed" on all platforms, and we don't + // want to require it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) + { + detail::_interpreter::get(); + + PyObject *mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject *axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) + { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) + { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) + { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + assert(x.size() == y.size()); + assert(y.size() == z.size()); - return res; -} + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *zarray = detail::get_array(z); -template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); - detail::_interpreter::get(); + // Build up the kw args. + PyObject *kwargs = PyDict_New(); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } + PyObject *fig_args = PyTuple_New(1); + PyObject *fig = nullptr; + PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); + PyObject *fig_exists = + PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); + if (!PyObject_IsTrue(fig_exists)) + { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + } + else + { + fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + fig_args); + } + Py_DECREF(fig_exists); + if (!fig) + throw std::runtime_error("Call to figure() failed."); + + PyObject *gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject *gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) + throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject *axis = PyObject_Call( + gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) + throw std::runtime_error("No axis"); + Py_INCREF(axis); + + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + PyObject *plot3 = PyObject_GetAttrString(axis, "scatter"); + if (!plot3) + throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject *res = PyObject_Call(plot3, args, kwargs); + if (!res) + throw std::runtime_error("Failed 3D line plot"); + Py_DECREF(plot3); + + Py_DECREF(axis); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(fig); + if (res) + Py_DECREF(res); + return res; + } - PyObject* pystring = PyString_FromString(s.c_str()); + template + bool boxplot(const std::vector> &data, + const std::vector &labels = {}, + const std::map &keywords = {}) + { + detail::_interpreter::get(); - 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 *listlist = detail::get_listlist(data); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, listlist); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + PyObject *kwargs = PyDict_New(); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + // kwargs needs the labels, if there are (the correct number of) labels + if (!labels.empty() && labels.size() == data.size()) + { + PyDict_SetItemString(kwargs, "labels", detail::get_array(labels)); + } - return res; -} + // take care of the remaining keywords + for (const auto &it : keywords) + { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } -template -bool contour(const std::vector& x, const std::vector& y, - const std::vector& z, - const std::map& keywords = {}) { - assert(x.size() == y.size() && x.size() == z.size()); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* zarray = detail::get_array(z); + Py_DECREF(args); + Py_DECREF(kwargs); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, zarray); + if (res) + Py_DECREF(res); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + return res; } - PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs); + template + bool boxplot(const std::vector &data, + const std::map &keywords = {}) + { + detail::_interpreter::get(); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + PyObject *vector = detail::get_array(data); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, vector); - return res; -} + PyObject *kwargs = PyDict_New(); + for (const auto &it : keywords) + { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } -template -bool quiver(const std::vector& x, const std::vector& y, const std::vector& u, const std::vector& w, const std::map& keywords = {}) -{ - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - detail::_interpreter::get(); + Py_DECREF(args); + Py_DECREF(kwargs); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* uarray = detail::get_array(u); - PyObject* warray = detail::get_array(w); + if (res) + Py_DECREF(res); - PyObject* plot_args = PyTuple_New(4); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, uarray); - PyTuple_SetItem(plot_args, 3, warray); + return res; + } + + template + bool bar(const std::vector &x, + const std::vector &y, + std::string ec = "black", + std::string ls = "-", + double lw = 1.0, + const std::map &keywords = {}) + { + detail::_interpreter::get(); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + + PyObject *kwargs = PyDict_New(); + + PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); + PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); + PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); + + for (std::map::const_iterator it = + keywords.begin(); + it != keywords.end(); + ++it) + { + PyDict_SetItemString( + kwargs, it->first.c_str(), PyUnicode_FromString(it->second.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_bar, plot_args, kwargs); + + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; + } + + template + bool bar(const std::vector &y, + std::string ec = "black", + std::string ls = "-", + double lw = 1.0, + const std::map &keywords = {}) + { + using T = typename std::remove_reference::type::value_type; + + detail::_interpreter::get(); + + std::vector x; + for (std::size_t i = 0; i < y.size(); i++) + { + x.push_back(i); + } + + return bar(x, y, ec, ls, lw, keywords); + } + + template + bool barh(const std::vector &x, const std::vector &y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map &keywords = {}) + { + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + + PyObject *kwargs = PyDict_New(); + + PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); + PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); + PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); + + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + 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_barh, plot_args, kwargs); + + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; + } + + inline bool subplots_adjust(const std::map &keywords = {}) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + detail::_interpreter::get(); + + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = + keywords.begin(); + it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyFloat_FromDouble(it->second)); + } + + PyObject *plot_args = PyTuple_New(0); + + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); + + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; } - PyObject* res = PyObject_Call( + template + bool named_hist(std::string label, const std::vector &y, long bins = 10, std::string color = "b", double alpha = 1.0) + { + detail::_interpreter::get(); + + PyObject *yarray = detail::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 + bool plot(const std::vector &x, const std::vector &y, const std::string &s = "") + { + assert(x.size() == y.size()); + + detail::_interpreter::get(); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::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 + bool contour(const std::vector &x, const std::vector &y, + const std::vector &z, + const std::map &keywords = {}) + { + assert(x.size() == y.size() && x.size() == z.size()); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *zarray = detail::get_array(z); + + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, zarray); + + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::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_contour, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); + + return res; + } + + template + bool quiver(const std::vector &x, const std::vector &y, const std::vector &u, const std::vector &w, const std::map &keywords = {}) + { + assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); + + detail::_interpreter::get(); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *uarray = detail::get_array(u); + PyObject *warray = detail::get_array(w); + + PyObject *plot_args = PyTuple_New(4); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, uarray); + PyTuple_SetItem(plot_args, 3, warray); + + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::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_quiver, plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; -} + return res; + } -template -bool quiver(const std::vector& x, const std::vector& y, const std::vector& z, const std::vector& u, const std::vector& w, const std::vector& v, const std::map& keywords = {}) -{ - //set up 3d axes stuff - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - //assert sizes match up - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size() && x.size() == z.size() && x.size() == v.size() && u.size() == v.size()); - - //set up parameters - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* zarray = detail::get_array(z); - PyObject* uarray = detail::get_array(u); - PyObject* warray = detail::get_array(w); - PyObject* varray = detail::get_array(v); - - PyObject* plot_args = PyTuple_New(6); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, zarray); - PyTuple_SetItem(plot_args, 3, uarray); - PyTuple_SetItem(plot_args, 4, warray); - PyTuple_SetItem(plot_args, 5, varray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - //get figure gca to enable 3d projection - PyObject *fig = - PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - //plot our boys bravely, plot them strongly, plot them with a wink and clap - PyObject *plot3 = PyObject_GetAttrString(axis, "quiver"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject* res = PyObject_Call( - plot3, plot_args, kwargs); - if (!res) throw std::runtime_error("Failed 3D plot"); - Py_DECREF(plot3); - Py_DECREF(axis); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); + template + bool quiver(const std::vector &x, const std::vector &y, const std::vector &z, const std::vector &u, const std::vector &w, const std::vector &v, const std::map &keywords = {}) + { + // set up 3d axes stuff + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) + { + detail::_interpreter::get(); + + PyObject *mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject *axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) + { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) + { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) + { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } + + // assert sizes match up + assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size() && x.size() == z.size() && x.size() == v.size() && u.size() == v.size()); + + // set up parameters + detail::_interpreter::get(); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *zarray = detail::get_array(z); + PyObject *uarray = detail::get_array(u); + PyObject *warray = detail::get_array(w); + PyObject *varray = detail::get_array(v); + + PyObject *plot_args = PyTuple_New(6); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, zarray); + PyTuple_SetItem(plot_args, 3, uarray); + PyTuple_SetItem(plot_args, 4, warray); + PyTuple_SetItem(plot_args, 5, varray); - detail::_interpreter::get(); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + // get figure gca to enable 3d projection + PyObject *fig = + PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple); + if (!fig) + throw std::runtime_error("Call to figure() failed."); + + PyObject *gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + + PyObject *gca = PyObject_GetAttrString(fig, "gca"); + if (!gca) + throw std::runtime_error("No gca"); + Py_INCREF(gca); + PyObject *axis = PyObject_Call( + gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); + + if (!axis) + throw std::runtime_error("No axis"); + Py_INCREF(axis); + Py_DECREF(gca); + Py_DECREF(gca_kwargs); + + // plot our boys bravely, plot them strongly, plot them with a wink and clap + PyObject *plot3 = PyObject_GetAttrString(axis, "quiver"); + if (!plot3) + throw std::runtime_error("No 3D line plot"); + Py_INCREF(plot3); + PyObject *res = PyObject_Call( + plot3, plot_args, kwargs); + if (!res) + throw std::runtime_error("Failed 3D plot"); + Py_DECREF(plot3); + Py_DECREF(axis); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - PyObject* pystring = PyString_FromString(s.c_str()); + return res; + } - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + template + bool stem(const std::vector &x, const std::vector &y, const std::string &s = "") + { + assert(x.size() == y.size()); - PyObject* res = PyObject_CallObject( + detail::_interpreter::get(); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::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); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; -} + return res; + } -template -bool semilogx(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); + template + bool semilogx(const std::vector &x, const std::vector &y, const std::string &s = "") + { + assert(x.size() == y.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - PyObject* pystring = PyString_FromString(s.c_str()); + 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 *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); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; -} + return res; + } -template -bool semilogy(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); + template + bool semilogy(const std::vector &x, const std::vector &y, const std::string &s = "") + { + assert(x.size() == y.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - PyObject* pystring = PyString_FromString(s.c_str()); + 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 *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); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; -} + return res; + } -template -bool loglog(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); + template + bool loglog(const std::vector &x, const std::vector &y, const std::string &s = "") + { + assert(x.size() == y.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - PyObject* pystring = PyString_FromString(s.c_str()); + 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 *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); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args); - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; -} + return res; + } -template -bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::map &keywords = {}) -{ - assert(x.size() == y.size()); + template + bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::map &keywords = {}) + { + assert(x.size() == y.size()); + + detail::_interpreter::get(); + + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *yerrarray = detail::get_array(yerr); + + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } + + PyDict_SetItemString(kwargs, "yerr", yerrarray); + + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* yerrarray = detail::get_array(yerr); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + + if (res) + Py_DECREF(res); + else + throw std::runtime_error("Call to errorbar() failed."); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + return res; } - PyDict_SetItemString(kwargs, "yerr", yerrarray); - - PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + template + bool named_plot(const std::string &name, const std::vector &y, const std::string &format = "") + { + detail::_interpreter::get(); - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - Py_DECREF(kwargs); - Py_DECREF(plot_args); + PyObject *yarray = detail::get_array(y); - if (res) - Py_DECREF(res); - else - throw std::runtime_error("Call to errorbar() failed."); + PyObject *pystring = PyString_FromString(format.c_str()); - return res; -} + PyObject *plot_args = PyTuple_New(2); -template -bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); + PyTuple_SetItem(plot_args, 0, yarray); + PyTuple_SetItem(plot_args, 1, pystring); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - PyObject* yarray = detail::get_array(y); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - PyObject* pystring = PyString_FromString(format.c_str()); + return res; + } - PyObject* plot_args = PyTuple_New(2); + template + bool named_plot(const std::string &name, const std::vector &x, const std::vector &y, const std::string &format = "") + { + detail::_interpreter::get(); - PyTuple_SetItem(plot_args, 0, yarray); - PyTuple_SetItem(plot_args, 1, pystring); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + PyObject *pystring = PyString_FromString(format.c_str()); - return res; -} + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + return res; + } - PyObject* pystring = PyString_FromString(format.c_str()); + template + bool named_semilogx(const std::string &name, const std::vector &x, const std::vector &y, const std::string &format = "") + { + detail::_interpreter::get(); - 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 *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + PyObject *pystring = PyString_FromString(format.c_str()); - return res; -} + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + return res; + } - PyObject* pystring = PyString_FromString(format.c_str()); + template + bool named_semilogy(const std::string &name, const std::vector &x, const std::vector &y, const std::string &format = "") + { + detail::_interpreter::get(); - 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 *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + PyObject *pystring = PyString_FromString(format.c_str()); - return res; -} + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + return res; + } - PyObject* pystring = PyString_FromString(format.c_str()); + template + bool named_loglog(const std::string &name, const std::vector &x, const std::vector &y, const std::string &format = "") + { + detail::_interpreter::get(); - 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 *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + PyObject *pystring = PyString_FromString(format.c_str()); - return res; -} + 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); -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + return res; + } - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + template + bool plot(const std::vector &y, const std::string &format = "") + { + std::vector x(y.size()); + for (size_t i = 0; i < x.size(); ++i) + x.at(i) = i; + return plot(x, y, format); + } - PyObject* pystring = PyString_FromString(format.c_str()); + template + bool plot(const std::vector &y, const std::map &keywords) + { + std::vector x(y.size()); + for (size_t i = 0; i < x.size(); ++i) + x.at(i) = i; + return plot(x, y, keywords); + } - 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); + template + bool stem(const std::vector &y, const std::string &format = "") + { + std::vector x(y.size()); + for (size_t i = 0; i < x.size(); ++i) + x.at(i) = i; + return stem(x, y, format); + } - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + template + void text(Numeric x, Numeric y, const std::string &s = "") + { + detail::_interpreter::get(); - return res; -} + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); + PyTuple_SetItem(args, 2, PyString_FromString(s.c_str())); -template -bool plot(const std::vector& y, const std::string& format = "") -{ - std::vector x(y.size()); - for(size_t i=0; i -bool plot(const std::vector& y, const std::map& keywords) -{ - std::vector x(y.size()); - for(size_t i=0; i -bool stem(const std::vector& y, const std::string& format = "") -{ - std::vector x(y.size()); - for (size_t i = 0; i < x.size(); ++i) x.at(i) = i; - return stem(x, y, format); -} + inline void colorbar(PyObject *mappable = NULL, const std::map &keywords = {}) + { + if (mappable == NULL) + throw std::runtime_error("Must call colorbar with PyObject* returned from an image, contour, surface, etc."); -template -void text(Numeric x, Numeric y, const std::string& s = "") -{ - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); - PyTuple_SetItem(args, 2, PyString_FromString(s.c_str())); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, mappable); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); - if(!res) throw std::runtime_error("Call to text() failed."); + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second)); + } - Py_DECREF(args); - Py_DECREF(res); -} + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); + if (!res) + throw std::runtime_error("Call to colorbar() failed."); -inline void colorbar(PyObject* mappable = NULL, const std::map& keywords = {}) -{ - if (mappable == NULL) - throw std::runtime_error("Must call colorbar with PyObject* returned from an image, contour, surface, etc."); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); + } - detail::_interpreter::get(); + inline long figure(long number = -1) + { + detail::_interpreter::get(); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, mappable); + PyObject *res; + if (number == -1) + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); + else + { + assert(number > 0); - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second)); - } + // Make sure interpreter is initialised + detail::_interpreter::get(); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); - if(!res) throw std::runtime_error("Call to colorbar() failed."); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromLong(number)); + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args); + Py_DECREF(args); + } - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + if (!res) + throw std::runtime_error("Call to figure() failed."); + PyObject *num = PyObject_GetAttrString(res, "number"); + if (!num) + throw std::runtime_error("Could not get number attribute of figure object"); + const long figureNumber = PyLong_AsLong(num); -inline long figure(long number = -1) -{ - detail::_interpreter::get(); + Py_DECREF(num); + Py_DECREF(res); - PyObject *res; - if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); - else { - assert(number > 0); + return figureNumber; + } - // Make sure interpreter is initialised + inline bool fignum_exists(long number) + { detail::_interpreter::get(); PyObject *args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromLong(number)); - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args); + if (!res) + throw std::runtime_error("Call to fignum_exists() failed."); + + bool ret = PyObject_IsTrue(res); + Py_DECREF(res); Py_DECREF(args); - } - if(!res) throw std::runtime_error("Call to figure() failed."); + return ret; + } - PyObject* num = PyObject_GetAttrString(res, "number"); - if (!num) throw std::runtime_error("Could not get number attribute of figure object"); - const long figureNumber = PyLong_AsLong(num); + inline void figure_size(size_t w, size_t h) + { + detail::_interpreter::get(); - Py_DECREF(num); - Py_DECREF(res); + const size_t dpi = 100; + PyObject *size = PyTuple_New(2); + PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); + PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); - return figureNumber; -} + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "figsize", size); + PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); -inline bool fignum_exists(long number) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple, kwargs); - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(number)); - PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args); - if(!res) throw std::runtime_error("Call to fignum_exists() failed."); + Py_DECREF(kwargs); - bool ret = PyObject_IsTrue(res); - Py_DECREF(res); - Py_DECREF(args); + if (!res) + throw std::runtime_error("Call to figure_size() failed."); + Py_DECREF(res); + } - return ret; -} + inline void legend() + { + detail::_interpreter::get(); -inline void figure_size(size_t w, size_t h) -{ - detail::_interpreter::get(); + 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."); - const size_t dpi = 100; - PyObject* size = PyTuple_New(2); - PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); - PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); + Py_DECREF(res); + } - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "figsize", size); - PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); + inline void legend(const std::map &keywords) + { + detail::_interpreter::get(); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - Py_DECREF(kwargs); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); + if (!res) + throw std::runtime_error("Call to legend() failed."); - if(!res) throw std::runtime_error("Call to figure_size() failed."); - Py_DECREF(res); -} + Py_DECREF(kwargs); + Py_DECREF(res); + } -inline void legend() -{ - detail::_interpreter::get(); + template + inline void set_aspect(Numeric ratio) + { + detail::_interpreter::get(); - 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."); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(ratio)); + PyObject *kwargs = PyDict_New(); - Py_DECREF(res); -} + PyObject *ax = + PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); + if (!ax) + throw std::runtime_error("Call to gca() failed."); + Py_INCREF(ax); -inline void legend(const std::map& keywords) -{ - detail::_interpreter::get(); + PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); + if (!set_aspect) + throw std::runtime_error("Attribute set_aspect not found."); + Py_INCREF(set_aspect); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::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(set_aspect, args, kwargs); + if (!res) + throw std::runtime_error("Call to set_aspect() failed."); + Py_DECREF(set_aspect); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); - if(!res) throw std::runtime_error("Call to legend() failed."); + Py_DECREF(ax); + Py_DECREF(args); + Py_DECREF(kwargs); + } - Py_DECREF(kwargs); - Py_DECREF(res); -} + inline void set_aspect_equal() + { + // expect ratio == "equal". Leaving error handling to matplotlib. + detail::_interpreter::get(); -template -inline void set_aspect(Numeric ratio) -{ - detail::_interpreter::get(); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyString_FromString("equal")); + PyObject *kwargs = PyDict_New(); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(ratio)); - PyObject* kwargs = PyDict_New(); + PyObject *ax = + PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); + if (!ax) + throw std::runtime_error("Call to gca() failed."); + Py_INCREF(ax); - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); - if (!ax) throw std::runtime_error("Call to gca() failed."); - Py_INCREF(ax); + PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); + if (!set_aspect) + throw std::runtime_error("Attribute set_aspect not found."); + Py_INCREF(set_aspect); - PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); - if (!set_aspect) throw std::runtime_error("Attribute set_aspect not found."); - Py_INCREF(set_aspect); + PyObject *res = PyObject_Call(set_aspect, args, kwargs); + if (!res) + throw std::runtime_error("Call to set_aspect() failed."); + Py_DECREF(set_aspect); - PyObject *res = PyObject_Call(set_aspect, args, kwargs); - if (!res) throw std::runtime_error("Call to set_aspect() failed."); - Py_DECREF(set_aspect); + Py_DECREF(ax); + Py_DECREF(args); + Py_DECREF(kwargs); + } - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); -} + template + void ylim(Numeric left, Numeric right) + { + detail::_interpreter::get(); -inline void set_aspect_equal() -{ - // expect ratio == "equal". Leaving error handling to matplotlib. - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString("equal")); - PyObject* kwargs = PyDict_New(); - - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); - if (!ax) throw std::runtime_error("Call to gca() failed."); - Py_INCREF(ax); - - PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); - if (!set_aspect) throw std::runtime_error("Attribute set_aspect not found."); - Py_INCREF(set_aspect); - - PyObject *res = PyObject_Call(set_aspect, args, kwargs); - if (!res) throw std::runtime_error("Call to set_aspect() failed."); - Py_DECREF(set_aspect); - - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); -} - -template -void ylim(Numeric left, Numeric right) -{ - detail::_interpreter::get(); + PyObject *list = PyList_New(2); + PyList_SetItem(list, 0, PyFloat_FromDouble(left)); + PyList_SetItem(list, 1, PyFloat_FromDouble(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* 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."); - 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); + } - Py_DECREF(args); - Py_DECREF(res); -} + template + void xlim(Numeric left, Numeric right) + { + detail::_interpreter::get(); -template -void xlim(Numeric left, Numeric right) -{ - detail::_interpreter::get(); + PyObject *list = PyList_New(2); + PyList_SetItem(list, 0, PyFloat_FromDouble(left)); + PyList_SetItem(list, 1, PyFloat_FromDouble(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* 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."); - 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); + } - Py_DECREF(args); - Py_DECREF(res); -} + inline std::array xlim() + { + PyObject *args = PyTuple_New(0); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + if (!res) + throw std::runtime_error("Call to xlim() failed."); -inline std::array xlim() -{ - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + Py_DECREF(res); - if(!res) throw std::runtime_error("Call to xlim() failed."); + PyObject *left = PyTuple_GetItem(res, 0); + PyObject *right = PyTuple_GetItem(res, 1); + return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; + } - Py_DECREF(res); + inline std::array 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); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -} + if (!res) + throw std::runtime_error("Call to ylim() failed."); + Py_DECREF(res); -inline std::array 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); + return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; + } - if(!res) throw std::runtime_error("Call to ylim() failed."); + template + inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map &keywords = {}) + { + assert(labels.size() == 0 || ticks.size() == labels.size()); - Py_DECREF(res); + detail::_interpreter::get(); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -} + // using numpy array + PyObject *ticksarray = detail::get_array(ticks); -template -inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); + PyObject *args; + if (labels.size() == 0) + { + // construct positional args + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, ticksarray); + } + else + { + // make tuple of tick labels + PyObject *labelstuple = PyTuple_New(labels.size()); + for (size_t i = 0; i < labels.size(); i++) + PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + + // construct positional args + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, ticksarray); + PyTuple_SetItem(args, 1, labelstuple); + } - detail::_interpreter::get(); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); - PyObject* args; - if(labels.size() == 0) { - // construct positional args - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, ticksarray); - } else { - // make tuple of tick labels - PyObject* labelstuple = PyTuple_New(labels.size()); - for (size_t i = 0; i < labels.size(); i++) - PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to xticks() failed"); - // construct positional args - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, ticksarray); - PyTuple_SetItem(args, 1, labelstuple); + Py_DECREF(res); } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + template + inline void xticks(const std::vector &ticks, const std::map &keywords) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + xticks(ticks, {}, keywords); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to xticks() failed"); + template + inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map &keywords = {}) + { + assert(labels.size() == 0 || ticks.size() == labels.size()); - Py_DECREF(res); -} + detail::_interpreter::get(); -template -inline void xticks(const std::vector &ticks, const std::map& keywords) -{ - xticks(ticks, {}, keywords); -} + // using numpy array + PyObject *ticksarray = detail::get_array(ticks); -template -inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); + PyObject *args; + if (labels.size() == 0) + { + // construct positional args + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, ticksarray); + } + else + { + // make tuple of tick labels + PyObject *labelstuple = PyTuple_New(labels.size()); + for (size_t i = 0; i < labels.size(); i++) + PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + + // construct positional args + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, ticksarray); + PyTuple_SetItem(args, 1, labelstuple); + } - detail::_interpreter::get(); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs); - PyObject* args; - if(labels.size() == 0) { - // construct positional args - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, ticksarray); - } else { - // make tuple of tick labels - PyObject* labelstuple = PyTuple_New(labels.size()); - for (size_t i = 0; i < labels.size(); i++) - PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to yticks() failed"); - // construct positional args - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, ticksarray); - PyTuple_SetItem(args, 1, labelstuple); + Py_DECREF(res); } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + template + inline void yticks(const std::vector &ticks, const std::map &keywords) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + yticks(ticks, {}, keywords); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to yticks() failed"); + template + inline void margins(Numeric margin) + { + // construct positional args + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); - Py_DECREF(res); -} + PyObject *res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); + if (!res) + throw std::runtime_error("Call to margins() failed."); -template -inline void yticks(const std::vector &ticks, const std::map& keywords) -{ - yticks(ticks, {}, keywords); -} + Py_DECREF(args); + Py_DECREF(res); + } -template inline void margins(Numeric margin) -{ - // construct positional args - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); + template + inline void margins(Numeric margin_x, Numeric margin_y) + { + // construct positional args + PyObject *args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin_x)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(margin_y)); - PyObject* res = + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); + if (!res) + throw std::runtime_error("Call to margins() failed."); + + Py_DECREF(args); + Py_DECREF(res); + } - Py_DECREF(args); - Py_DECREF(res); -} + inline void tick_params(const std::map &keywords, const std::string axis = "both") + { + detail::_interpreter::get(); -template inline void margins(Numeric margin_x, Numeric margin_y) -{ - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin_x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(margin_y)); + // construct positional args + PyObject *args; + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str())); - PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - Py_DECREF(args); - Py_DECREF(res); -} + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to tick_params() failed"); -inline void tick_params(const std::map& keywords, const std::string axis = "both") -{ - detail::_interpreter::get(); + Py_DECREF(res); + } - // construct positional args - PyObject* args; - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str())); + inline void subplot(long nrows, long ncols, long plot_number) + { + detail::_interpreter::get(); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } + // 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."); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); + Py_DECREF(args); + Py_DECREF(res); + } - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) throw std::runtime_error("Call to tick_params() failed"); + inline void subplot2grid(long nrows, long ncols, long rowid = 0, long colid = 0, long rowspan = 1, long colspan = 1) + { + detail::_interpreter::get(); - Py_DECREF(res); -} + PyObject *shape = PyTuple_New(2); + PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); + PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); -inline void subplot(long nrows, long ncols, long plot_number) -{ - detail::_interpreter::get(); + PyObject *loc = PyTuple_New(2); + PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); + PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); - // 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 *args = PyTuple_New(4); + PyTuple_SetItem(args, 0, shape); + PyTuple_SetItem(args, 1, loc); + PyTuple_SetItem(args, 2, PyLong_FromLong(rowspan)); + PyTuple_SetItem(args, 3, PyLong_FromLong(colspan)); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); - if(!res) throw std::runtime_error("Call to subplot() failed."); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot2grid, args); + if (!res) + throw std::runtime_error("Call to subplot2grid() failed."); - Py_DECREF(args); - Py_DECREF(res); -} + Py_DECREF(shape); + Py_DECREF(loc); + Py_DECREF(args); + Py_DECREF(res); + } -inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -{ - detail::_interpreter::get(); + inline void title(const std::string &titlestr, const std::map &keywords = {}) + { + detail::_interpreter::get(); - PyObject* shape = PyTuple_New(2); - PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); - PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); + PyObject *pytitlestr = PyString_FromString(titlestr.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pytitlestr); + + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* loc = PyTuple_New(2); - PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); - PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); + if (!res) + throw std::runtime_error("Call to title() failed."); - PyObject* args = PyTuple_New(4); - PyTuple_SetItem(args, 0, shape); - PyTuple_SetItem(args, 1, loc); - PyTuple_SetItem(args, 2, PyLong_FromLong(rowspan)); - PyTuple_SetItem(args, 3, PyLong_FromLong(colspan)); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); + } - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot2grid, args); - if(!res) throw std::runtime_error("Call to subplot2grid() failed."); + inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) + { + detail::_interpreter::get(); - Py_DECREF(shape); - Py_DECREF(loc); - Py_DECREF(args); - Py_DECREF(res); -} + PyObject *pysuptitlestr = PyString_FromString(suptitlestr.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pysuptitlestr); -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pytitlestr); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); + if (!res) + throw std::runtime_error("Call to suptitle() failed."); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); - if(!res) throw std::runtime_error("Call to title() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + inline void axis(const std::string &axisstr) + { + detail::_interpreter::get(); -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); + PyObject *str = PyString_FromString(axisstr.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, str); - PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pysuptitlestr); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); + if (!res) + throw std::runtime_error("Call to title() failed."); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + Py_DECREF(args); + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); - if(!res) throw std::runtime_error("Call to suptitle() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void axis(const std::string &axisstr) -{ - detail::_interpreter::get(); - - PyObject* str = PyString_FromString(axisstr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); + inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map &keywords = std::map()) + { + detail::_interpreter::get(); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(y)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmin)); + PyTuple_SetItem(args, 2, PyFloat_FromDouble(xmax)); - Py_DECREF(args); - Py_DECREF(res); -} + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } -inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_axhline, args, kwargs); - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(y)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmin)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(xmax)); + Py_DECREF(args); + Py_DECREF(kwargs); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + if (res) + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axhline, args, kwargs); + inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map &keywords = std::map()) + { + detail::_interpreter::get(); - Py_DECREF(args); - Py_DECREF(kwargs); + // construct positional args + PyObject *args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(ymin)); + PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymax)); - if(res) Py_DECREF(res); -} + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } -inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, kwargs); - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(ymin)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymax)); + Py_DECREF(args); + Py_DECREF(kwargs); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + if (res) + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); -} + inline void axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1., const std::map &keywords = std::map()) + { + // construct positional args + PyObject *args = PyTuple_New(4); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(xmin)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmax)); + PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymin)); + PyTuple_SetItem(args, 3, PyFloat_FromDouble(ymax)); -inline void axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ - // construct positional args - PyObject* args = PyTuple_New(4); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(xmin)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmax)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymin)); - PyTuple_SetItem(args, 3, PyFloat_FromDouble(ymax)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if (it->first == "linewidth" || it->first == "alpha") { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); - } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvspan, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); -} - -inline void xlabel(const std::string &str, const std::map &keywords = {}) -{ - detail::_interpreter::get(); + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + if (it->first == "linewidth" || it->first == "alpha") + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyFloat_FromDouble(std::stod(it->second))); + } + else + { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } + } - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_axvspan, args, kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + if (res) + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); + inline void xlabel(const std::string &str, const std::map &keywords = {}) + { + detail::_interpreter::get(); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + PyObject *pystr = PyString_FromString(str.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); -inline void ylabel(const std::string &str, const std::map& keywords = {}) -{ - detail::_interpreter::get(); + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to xlabel() failed."); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); - if(!res) throw std::runtime_error("Call to ylabel() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + inline void ylabel(const std::string &str, const std::map &keywords = {}) + { + detail::_interpreter::get(); -inline void set_zlabel(const std::string &str, const std::map& keywords = {}) -{ - detail::_interpreter::get(); + PyObject *pystr = PyString_FromString(str.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to ylabel() failed."); - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); + inline void set_zlabel(const std::string &str, const std::map &keywords = {}) + { + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } + // Same as with plot_surface: We lazily load the modules here the first time + // this function is called because I'm not sure that we can assume "matplotlib + // installed" implies "mpl_toolkits installed" on all platforms, and we don't + // want to require it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) + { + PyObject *mpl_toolkits = PyString_FromString("mpl_toolkits"); + PyObject *axis3d = PyString_FromString("mpl_toolkits.mplot3d"); + if (!mpl_toolkits || !axis3d) + { + throw std::runtime_error("couldnt create string"); + } + + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) + { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) + { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); - if (!ax) throw std::runtime_error("Call to gca() failed."); - Py_INCREF(ax); + PyObject *pystr = PyString_FromString(str.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); - PyObject *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); - if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); - Py_INCREF(zlabel); + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } - PyObject *res = PyObject_Call(zlabel, args, kwargs); - if (!res) throw std::runtime_error("Call to set_zlabel() failed."); - Py_DECREF(zlabel); + PyObject *ax = + PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, + detail::_interpreter::get().s_python_empty_tuple); + if (!ax) + throw std::runtime_error("Call to gca() failed."); + Py_INCREF(ax); - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} + PyObject *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); + if (!zlabel) + throw std::runtime_error("Attribute set_zlabel not found."); + Py_INCREF(zlabel); -inline void grid(bool flag) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_Call(zlabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to set_zlabel() failed."); + Py_DECREF(zlabel); - PyObject* pyflag = flag ? Py_True : Py_False; - Py_INCREF(pyflag); + Py_DECREF(ax); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + } - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyflag); + inline void grid(bool flag) + { + detail::_interpreter::get(); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); + PyObject *pyflag = flag ? Py_True : Py_False; + Py_INCREF(pyflag); - Py_DECREF(args); - Py_DECREF(res); -} + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyflag); -inline void show(const bool block = true) -{ - detail::_interpreter::get(); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); + if (!res) + throw std::runtime_error("Call to grid() failed."); - PyObject* res; - if(block) - { - res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_show, - detail::_interpreter::get().s_python_empty_tuple); + Py_DECREF(args); + Py_DECREF(res); } - else + + inline void show(const bool block = true) { - 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); - } + detail::_interpreter::get(); + 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."); + if (!res) + throw std::runtime_error("Call to show() failed."); - Py_DECREF(res); -} + Py_DECREF(res); + } -inline void close() -{ - detail::_interpreter::get(); + inline void close() + { + detail::_interpreter::get(); - PyObject* res = PyObject_CallObject( + 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() { - detail::_interpreter::get(); - - PyObject* res; - PyObject *kwargs = PyDict_New(); - - res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + if (!res) + throw std::runtime_error("Call to close() failed."); - Py_DECREF(kwargs); - - if (!res) - throw std::runtime_error("Call to show() failed."); - - Py_DECREF(res); -} - -inline void draw() -{ - detail::_interpreter::get(); - - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_draw, - detail::_interpreter::get().s_python_empty_tuple); + Py_DECREF(res); + } - if (!res) throw std::runtime_error("Call to draw() failed."); + inline void xkcd() + { + detail::_interpreter::get(); - Py_DECREF(res); -} + PyObject *res; + PyObject *kwargs = PyDict_New(); -template -inline void pause(Numeric interval) -{ - detail::_interpreter::get(); + res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, + detail::_interpreter::get().s_python_empty_tuple, kwargs); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); + Py_DECREF(kwargs); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); - if(!res) throw std::runtime_error("Call to pause() failed."); + if (!res) + throw std::runtime_error("Call to show() failed."); - Py_DECREF(args); - Py_DECREF(res); -} + Py_DECREF(res); + } -inline void save(const std::string& filename, const int dpi=0) -{ - detail::_interpreter::get(); + inline void draw() + { + detail::_interpreter::get(); - PyObject* pyfilename = PyString_FromString(filename.c_str()); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_draw, + detail::_interpreter::get().s_python_empty_tuple); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyfilename); + if (!res) + throw std::runtime_error("Call to draw() failed."); - PyObject* kwargs = PyDict_New(); + Py_DECREF(res); + } - if(dpi > 0) + template + inline void pause(Numeric interval) { - PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); - } + detail::_interpreter::get(); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_save, args, kwargs); - if (!res) throw std::runtime_error("Call to save() failed."); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); + if (!res) + throw std::runtime_error("Call to pause() failed."); -inline void rcparams(const std::map& keywords = {}) { - detail::_interpreter::get(); - PyObject* args = PyTuple_New(0); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if ("text.usetex" == it->first) - PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); - else PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + Py_DECREF(args); + Py_DECREF(res); } - - PyObject * update = PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update"); - PyObject * res = PyObject_Call(update, args, kwargs); - if(!res) throw std::runtime_error("Call to rcParams.update() failed."); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(update); - Py_DECREF(res); -} - -inline void clf() { - detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); + inline void save(const std::string &filename, const int dpi = 0) + { + detail::_interpreter::get(); - if (!res) throw std::runtime_error("Call to clf() failed."); + PyObject *pyfilename = PyString_FromString(filename.c_str()); - Py_DECREF(res); -} + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyfilename); -inline void cla() { - detail::_interpreter::get(); + PyObject *kwargs = PyDict_New(); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, - detail::_interpreter::get().s_python_empty_tuple); + if (dpi > 0) + { + PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); + } - if (!res) - throw std::runtime_error("Call to cla() failed."); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_save, args, kwargs); + if (!res) + throw std::runtime_error("Call to save() failed."); - Py_DECREF(res); -} + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); + } -inline void ion() { - detail::_interpreter::get(); + inline void rcparams(const std::map &keywords = {}) + { + detail::_interpreter::get(); + PyObject *args = PyTuple_New(0); + PyObject *kwargs = PyDict_New(); + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { + if ("text.usetex" == it->first) + PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); + else + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); + PyObject *update = PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update"); + PyObject *res = PyObject_Call(update, args, kwargs); + if (!res) + throw std::runtime_error("Call to rcParams.update() failed."); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(update); + Py_DECREF(res); + } - if (!res) throw std::runtime_error("Call to ion() failed."); + inline void clf() + { + detail::_interpreter::get(); - Py_DECREF(res); -} + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_clf, + detail::_interpreter::get().s_python_empty_tuple); -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ - detail::_interpreter::get(); + if (!res) + throw std::runtime_error("Call to clf() failed."); - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); + Py_DECREF(res); + } - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + inline void cla() { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } + detail::_interpreter::get(); - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_ginput, args, kwargs); + PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, + detail::_interpreter::get().s_python_empty_tuple); - Py_DECREF(kwargs); - Py_DECREF(args); - if (!res) throw std::runtime_error("Call to ginput() failed."); + if (!res) + throw std::runtime_error("Call to cla() failed."); - const size_t len = PyList_Size(res); - std::vector> out; - out.reserve(len); - for (size_t i = 0; i < len; i++) { - PyObject *current = PyList_GetItem(res, i); - std::array position; - position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0)); - position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1)); - out.push_back(position); + Py_DECREF(res); } - Py_DECREF(res); - - return out; -} -// Actually, is there any reason not to call this automatically for every plot? -inline void tight_layout() { - detail::_interpreter::get(); + inline void ion() + { + detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_tight_layout, - detail::_interpreter::get().s_python_empty_tuple); + 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 tight_layout() failed."); + if (!res) + throw std::runtime_error("Call to ion() failed."); - Py_DECREF(res); -} + Py_DECREF(res); + } -// Support for variadic plot() and initializer lists: + inline std::vector> ginput(const int numClicks = 1, const std::map &keywords = {}) + { + detail::_interpreter::get(); -namespace detail { + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); -template -using is_function = typename std::is_function>>::type; + // construct keyword args + PyObject *kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + } -template -struct is_callable_impl; + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_ginput, args, kwargs); -template -struct is_callable_impl -{ - typedef is_function type; -}; // a non-object is callable iff it is a function + Py_DECREF(kwargs); + Py_DECREF(args); + if (!res) + throw std::runtime_error("Call to ginput() failed."); -template -struct is_callable_impl -{ - struct Fallback { void operator()(); }; - struct Derived : T, Fallback { }; + const size_t len = PyList_Size(res); + std::vector> out; + out.reserve(len); + for (size_t i = 0; i < len; i++) + { + PyObject *current = PyList_GetItem(res, i); + std::array position; + position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0)); + position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1)); + out.push_back(position); + } + Py_DECREF(res); - template struct Check; + return out; + } - template - static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match + // Actually, is there any reason not to call this automatically for every plot? + inline void tight_layout() + { + detail::_interpreter::get(); - template - static std::false_type test( Check* ); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_tight_layout, + detail::_interpreter::get().s_python_empty_tuple); -public: - typedef decltype(test(nullptr)) type; - typedef decltype(&Fallback::operator()) dtype; - static constexpr bool value = type::value; -}; // an object is callable iff it defines operator() + if (!res) + throw std::runtime_error("Call to tight_layout() failed."); -template -struct is_callable -{ - // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not - typedef typename is_callable_impl::value, T>::type type; -}; + Py_DECREF(res); + } -template -struct plot_impl { }; + // Support for variadic plot() and initializer lists: -template<> -struct plot_impl -{ - template - bool operator()(const IterableX& x, const IterableY& y, const std::string& format) + namespace detail { - detail::_interpreter::get(); - - // 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!"); + template + using is_function = typename std::is_function>>::type; - PyObject* xlist = PyList_New(xs); - PyObject* ylist = PyList_New(ys); - PyObject* pystring = PyString_FromString(format.c_str()); + template + struct is_callable_impl; - 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); + template + struct is_callable_impl + { + typedef is_function type; + }; // a non-object is callable iff it is a function - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + template + struct is_callable_impl + { + struct Fallback + { + void operator()(); + }; + struct Derived : T, Fallback + { + }; + + template + struct Check; + + template + static std::true_type test(...); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match + + template + static std::false_type test(Check *); + + public: + typedef decltype(test(nullptr)) type; + typedef decltype(&Fallback::operator()) dtype; + static constexpr bool value = type::value; + }; // an object is callable iff it defines operator() + + template + struct is_callable + { + // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not + typedef typename is_callable_impl::value, T>::type type; + }; - Py_DECREF(plot_args); - if(res) Py_DECREF(res); + template + struct plot_impl + { + }; - return res; + template <> + struct plot_impl + { + template + bool operator()(const IterableX &x, const IterableY &y, const std::string &format) + { + detail::_interpreter::get(); + + // 2-phase lookup for distance, begin, end + using std::begin; + using std::distance; + 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 + { + template + 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 y; + for (auto x : ticks) + y.push_back(f(x)); + return plot_impl()(ticks, y, format); + } + }; + + } // end namespace detail + + // recursion stop for the above + template + bool plot() { return true; } + + template + bool plot(const A &a, const B &b, const std::string &format, Args... args) + { + return detail::plot_impl::type>()(a, b, format) && plot(args...); } -}; -template<> -struct plot_impl -{ - template - bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) + /* + * 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 &x, const std::vector &y, 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 y; - for(auto x : ticks) y.push_back(f(x)); - return plot_impl()(ticks,y,format); + return plot(x, y, format); } -}; -} // end namespace detail - -// recursion stop for the above -template -bool plot() { return true; } + inline bool plot(const std::vector &y, const std::string &format = "") + { + return plot(y, format); + } -template -bool plot(const A& a, const B& b, const std::string& format, Args... args) -{ - return detail::plot_impl::type>()(a,b,format) && plot(args...); -} + inline bool plot(const std::vector &x, const std::vector &y, const std::map &keywords) + { + return plot(x, y, keywords); + } -/* - * 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& x, const std::vector& y, const std::string& format = "") { - return plot(x,y,format); -} + /* + * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting + */ + class Plot + { + public: + // default initialization with plot label, some data and format + template + Plot(const std::string &name, const std::vector &x, const std::vector &y, const std::string &format = "") + { + detail::_interpreter::get(); -inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(y,format); -} + assert(x.size() == y.size()); -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); -} + PyObject *kwargs = PyDict_New(); + if (name != "") + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); -/* - * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting - */ -class Plot -{ -public: - // default initialization with plot label, some data and format - template - Plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { - detail::_interpreter::get(); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - assert(x.size() == y.size()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* kwargs = PyDict_New(); - if(name != "") - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.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* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - PyObject* pystring = PyString_FromString(format.c_str()); + Py_DECREF(kwargs); + Py_DECREF(plot_args); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + if (res) + { + line = PyList_GetItem(res, 0); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + if (line) + set_data_fct = PyObject_GetAttrString(line, "set_data"); + else + Py_DECREF(line); + Py_DECREF(res); + } + } - Py_DECREF(kwargs); - Py_DECREF(plot_args); + // shorter initialization with name or format only + // basically calls line, = plot([], []) + Plot(const std::string &name = "", const std::string &format = "") + : Plot(name, std::vector(), std::vector(), format) {} - if(res) + template + bool update(const std::vector &x, const std::vector &y) { - line= PyList_GetItem(res, 0); - - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); - else - Py_DECREF(line); - Py_DECREF(res); + assert(x.size() == y.size()); + if (set_data_fct) + { + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + + PyObject *res = PyObject_CallObject(set_data_fct, plot_args); + if (res) + Py_DECREF(res); + return res; + } + return false; } - } - // shorter initialization with name or format only - // basically calls line, = plot([], []) - Plot(const std::string& name = "", const std::string& format = "") - : Plot(name, std::vector(), std::vector(), format) {} - - template - bool update(const std::vector& x, const std::vector& y) { - assert(x.size() == y.size()); - if(set_data_fct) + // clears the plot but keep it available + bool clear() { - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject* res = PyObject_CallObject(set_data_fct, plot_args); - if (res) Py_DECREF(res); - return res; + return update(std::vector(), std::vector()); } - return false; - } - - // clears the plot but keep it available - bool clear() { - return update(std::vector(), std::vector()); - } - // definitely remove this line - void remove() { - if(line) + // definitely remove this line + void remove() { - auto remove_fct = PyObject_GetAttrString(line,"remove"); - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(remove_fct, args); - if (res) Py_DECREF(res); + if (line) + { + auto remove_fct = PyObject_GetAttrString(line, "remove"); + PyObject *args = PyTuple_New(0); + PyObject *res = PyObject_CallObject(remove_fct, args); + if (res) + Py_DECREF(res); + } + decref(); } - decref(); - } - ~Plot() { - decref(); - } -private: - - void decref() { - if(line) - Py_DECREF(line); - if(set_data_fct) - Py_DECREF(set_data_fct); - } + ~Plot() + { + decref(); + } + private: + void decref() + { + if (line) + Py_DECREF(line); + if (set_data_fct) + Py_DECREF(set_data_fct); + } - PyObject* line = nullptr; - PyObject* set_data_fct = nullptr; -}; + PyObject *line = nullptr; + PyObject *set_data_fct = nullptr; + }; } // end namespace matplotlibcpp