From ce6598ad78cf63213a69c5e5e58a185de38bfdc2 Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Thu, 28 Mar 2024 16:06:37 -0400 Subject: [PATCH 1/7] cleanup --- .gitignore | 3 + .travis.yml | 6 - CMakeLists.txt | 143 ++-------- LICENSE | 21 -- LICENSE.matplotlib | 47 ---- README.md | 297 +-------------------- cmake/matplotlib_cppConfig.cmake.in | 10 - contrib/Dockerfile | 27 -- contrib/Makefile | 6 - contrib/README.md | 32 --- contrib/WinBuild.cmd | 61 ----- examples/.gitignore | 14 - examples/animation.cpp | 36 --- examples/animation.gif | Bin 33288 -> 0 bytes examples/bar.cpp | 18 -- examples/bar.png | Bin 11952 -> 0 bytes examples/basic.cpp | 44 --- examples/basic.png | Bin 37402 -> 0 bytes examples/colorbar.cpp | 32 --- examples/contour.cpp | 24 -- examples/fill.cpp | 35 --- examples/fill.png | Bin 62995 -> 0 bytes examples/fill_between.png | Bin 24970 -> 0 bytes examples/fill_inbetween.cpp | 28 -- examples/imshow.cpp | 29 -- examples/lines3d.cpp | 30 --- examples/lines3d.png | Bin 76500 -> 0 bytes examples/minimal.cpp | 10 +- examples/minimal.png | Bin 20174 -> 0 bytes examples/modern.cpp | 33 --- examples/modern.png | Bin 30389 -> 0 bytes examples/nonblock.cpp | 46 ---- examples/quiver.cpp | 20 -- examples/quiver.png | Bin 39752 -> 0 bytes examples/spy.cpp | 30 --- examples/subplot.cpp | 31 --- examples/subplot2grid.cpp | 44 --- examples/surface.cpp | 24 -- examples/surface.png | Bin 106199 -> 0 bytes examples/update.cpp | 60 ----- examples/xkcd.cpp | 22 -- examples/xkcd.png | Bin 79452 -> 0 bytes matplotlibcpp.h => include/matplotlibcpp.h | 0 run.sh | 16 ++ 44 files changed, 46 insertions(+), 1233 deletions(-) delete mode 100644 .travis.yml delete mode 100644 LICENSE delete mode 100644 LICENSE.matplotlib delete mode 100644 cmake/matplotlib_cppConfig.cmake.in delete mode 100644 contrib/Dockerfile delete mode 100644 contrib/Makefile delete mode 100644 contrib/README.md delete mode 100644 contrib/WinBuild.cmd delete mode 100644 examples/.gitignore delete mode 100644 examples/animation.cpp delete mode 100644 examples/animation.gif delete mode 100644 examples/bar.cpp delete mode 100644 examples/bar.png delete mode 100644 examples/basic.cpp delete mode 100644 examples/basic.png delete mode 100644 examples/colorbar.cpp delete mode 100644 examples/contour.cpp delete mode 100644 examples/fill.cpp delete mode 100644 examples/fill.png delete mode 100644 examples/fill_between.png delete mode 100644 examples/fill_inbetween.cpp delete mode 100644 examples/imshow.cpp delete mode 100644 examples/lines3d.cpp delete mode 100644 examples/lines3d.png delete mode 100644 examples/minimal.png delete mode 100644 examples/modern.cpp delete mode 100644 examples/modern.png delete mode 100644 examples/nonblock.cpp delete mode 100644 examples/quiver.cpp delete mode 100644 examples/quiver.png delete mode 100644 examples/spy.cpp delete mode 100644 examples/subplot.cpp delete mode 100644 examples/subplot2grid.cpp delete mode 100644 examples/surface.cpp delete mode 100644 examples/surface.png delete mode 100644 examples/update.cpp delete mode 100644 examples/xkcd.cpp delete mode 100644 examples/xkcd.png rename matplotlibcpp.h => include/matplotlibcpp.h (100%) create mode 100644 run.sh diff --git a/.gitignore b/.gitignore index 1c4a1b0..355708e 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ # vim temp files *.sw* + +# CMake +build/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d6175a2..0000000 --- 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 bb2decd..b22c5b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,133 +1,24 @@ -cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -project(matplotlib_cpp LANGUAGES CXX) +# CMakeLists.txt +cmake_minimum_required(VERSION 3.15) +project("example" LANGUAGES CXX) -include(GNUInstallDirs) -set(PACKAGE_NAME matplotlib_cpp) -set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/${PACKAGE_NAME}/cmake) +set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings") # bypass dev warnings -# 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 - ) -else() - target_compile_definitions(matplotlib_cpp INTERFACE WITHOUT_NUMPY) -endif() -install( - TARGETS matplotlib_cpp - EXPORT install_targets -) +# find python libraries +find_package(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) +find_package(PythonLibs 3.0 REQUIRED) +include_directories(${PYTHON3_INCLUDE_DIRS} ${NumPy_INCLUDE_DIRS}) +# populate matplotlib repository +include_directories(include/) -# Examples +# add executable 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") - -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") - -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") - -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") - -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_executable(lines3d examples/lines3d.cpp) -target_link_libraries(lines3d PRIVATE matplotlib_cpp) -set_target_properties(lines3d PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -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") - - 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") - - 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} -) +# link python and numpy +target_link_libraries(minimal + PRIVATE + ${PYTHON_LIBRARIES} + Python3::NumPy +) \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a67f2b5..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Benno Evers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/LICENSE.matplotlib b/LICENSE.matplotlib deleted file mode 100644 index 1c1a66b..0000000 --- a/LICENSE.matplotlib +++ /dev/null @@ -1,47 +0,0 @@ -This library does not contain any files from the matplotlib project, nor -does it make any changes to it. On the other hand, the code contained herein -is perfectly useless without a separate installation of matplotlib. -I don't know enough about US copyright law to decide whether this implies -that this library "uses" or is "based on" matplotlib. -In any case, matplotlib comes with the following license: - -License agreement for matplotlib 1.4.3 -1. This LICENSE AGREEMENT is between the Matplotlib Development Team (“MDT”), - and the Individual or Organization (“Licensee”) accessing and otherwise - using matplotlib software in source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, MDT hereby grants - Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, - test, perform and/or display publicly, prepare derivative works, distribute, and - otherwise use matplotlib 1.4.3 alone or in any derivative version, provided, however, - that MDT’s License Agreement and MDT’s notice of copyright, i.e., - “Copyright (c) 2012-2013 Matplotlib Development Team; All Rights Reserved” are retained - in matplotlib 1.4.3 alone or in any derivative version prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on or incorporates - matplotlib 1.4.3 or any part thereof, and wants to make the derivative work available - to others as provided herein, then Licensee hereby agrees to include in any such work a - brief summary of the changes made to matplotlib 1.4.3. - -4. MDT is making matplotlib 1.4.3 available to Licensee on an “AS IS” basis. MDT MAKES NO - REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, - MDT MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS - FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 1.4.3 WILL NOT INFRINGE ANY - THIRD PARTY RIGHTS. - -5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB 1.4.3 FOR ANY - INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, - DISTRIBUTING, OR OTHERWISE USING MATPLOTLIB 1.4.3, OR ANY DERIVATIVE THEREOF, - EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material breach of - its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any relationship of - agency, partnership, or joint venture between MDT and Licensee. This License - Agreement does not grant permission to use MDT trademarks or trade name in a - trademark sense to endorse or promote products or services of Licensee, or any - third party. - -8. By copying, installing or otherwise using matplotlib 1.4.3, Licensee agrees to be - bound by the terms and conditions of this License Agreement. diff --git a/README.md b/README.md index 0f8479f..32fc63e 100644 --- a/README.md +++ b/README.md @@ -1,294 +1,7 @@ -matplotlib-cpp -============== +# MATPLOTLIBCPP - FORKED BY ARRI -Welcome to matplotlib-cpp, possibly the simplest C++ plotting library. -It is built to resemble the plotting API used by Matlab and matplotlib. +This is a fork of the original [matplotlib-cpp](https://github.com/lava/matplotlib-cpp). Its characterized for being: - - -Usage ------ -Complete minimal example: -```cpp -#include "matplotlibcpp.h" -namespace plt = matplotlibcpp; -int main() { - plt::plot({1,3,2,4}); - plt::show(); -} -``` - g++ minimal.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 - -**Result:** - -![Minimal example](./examples/minimal.png) - -A more comprehensive example: -```cpp -#include "matplotlibcpp.h" -#include - -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); - 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. - -* It would be nice to have a more object-oriented design with a Plot class which would allow - multiple independent plots per program. - -* Right now, only a small subset of matplotlibs functionality is exposed. Stuff like xlabel()/ylabel() etc. should - be easy to add. - -* If you use Anaconda on Windows, you might need to set PYTHONHOME to Anaconda home directory and QT_QPA_PLATFORM_PLUGIN_PATH to %PYTHONHOME%Library/plugins/platforms. The latter is for especially when you get the error which says 'This application failed to start because it could not find or load the Qt platform plugin "windows" -in "".' - -* MacOS: `Unable to import matplotlib.pyplot`. Cause: In mac os image rendering back end of matplotlib (what-is-a-backend to render using the API of Cocoa by default). There is Qt4Agg and GTKAgg and as a back-end is not the default. Set the back end of macosx that is differ compare with other windows or linux os. -Solution is described [here](https://stackoverflow.com/questions/21784641/installation-issue-with-matplotlib-python?noredirect=1&lq=1), additional information can be found there too(see links in answers). +- minimal: Just the necessary files. +- cmake-friendly: Compile from cmake! +- extended 3D rendering: Copied from [this video](https://www.youtube.com/watch?v=NOZDyFmWDtw) diff --git a/cmake/matplotlib_cppConfig.cmake.in b/cmake/matplotlib_cppConfig.cmake.in deleted file mode 100644 index 86d25d0..0000000 --- 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 850466f..0000000 --- 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 f659cd9..0000000 --- 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 0af8515..0000000 --- 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 9dfd627..0000000 --- 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/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 3da8ad6..0000000 --- a/examples/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -animation -bar -basic -fill -fill_inbetween -imshow -minimal -modern -nonblock -quiver -subplot -surface -update -xkcd diff --git a/examples/animation.cpp b/examples/animation.cpp deleted file mode 100644 index d979430..0000000 --- a/examples/animation.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#define _USE_MATH_DEFINES -#include -#include "../matplotlibcpp.h" - -namespace plt = matplotlibcpp; - -int main() -{ - int n = 1000; - std::vector x, y, z; - - for(int i=0; iVZFCFncw`$I%T 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
BP>FuN0d=u+s++oOQ=aYxW zfQMhX(>Q!`CNJt@=IdWU(a>sEeEqf8@)X0VXu`cq%)R^d2ga_9*L!)3=vS2uKwqv* zrMeAfHHY;xH1wxjfXov0xY(>385VFOvGM8fZPfhy#ZF=TSs~TFd_@emEh;1CD9=c; zj5})&%417+aL6^H2dN9U2Zn;7)LO6Np;G1|8~+2;hKuA1nAo;5?A{EwNvW)J^q#)H zQ@-Q9ck9c=v)q}Pq9f?_ycGxWQogjlQaWp((Wo>J>IiXwEPpN>RV@p5Q&10Dx#{6j zo04V1G8KHRq<~JnMT-OCXYI9e1k7ST^B8SGpM|9}O9+7?hjkXA11nflnLO1c3w!pk zG9r*=ProZh@baz6Jk;B6`h-UZMzKOeAHy6xa z&n7%rH^uOKBNHFB;C;X$tHAp>tD;a2AQ@N?>EI+#l*G?`IfoAdeJIBNO~y3!J&etD z{@9HCni>bvZx)3GoF8T!6#@uLUd{Zs|wb(qk&lci{{-lJK%>)wk=OyJPUWO9#&% ze0qsRroNv)jB|tcfXCcFCu8tM?Y66|Tt}5P_4oktfkz5FU)sBFpNAHSM#BkHlkYyh z4C-Ft!Q>vOQr4|JBqD1zM^+C2v4zk8AfVfrfuv}w*nnRm%f7L?BiAGdcwGS1(k<>X z3JF`N3s^4!|=fsFp+Vw3^3%O^(TKaZ1F5ND zyx!5@-Sf~WMRd=}2m8bAsWWvpHfag?@!slgRbMWFJcu}3S7Qq%CtKeN`sZ3k>z#|& zBJr)eUv2K_6ch(^uFYydRTKPR_D3Q} zy)-csv(g}Ll%%M`GRQeIVktjfSXHJ!fSQg#*@@yeD@SB4Xq$ua-}esCICeIB1Lp?9 z^>&*qmH1Pq(T{8D>_g@6uQ?%gr+-V`O8WbZl+)7l{psipQ;3Gt3fp!H{2w?rvp|6< zxj67+(%jAdfb0MGfuI=`Yy)uHLt>u7ZSNl@MjFIt)%BIWwPMS0;E^Daxb9fnl4CnQ&R2Bw)*mht;NwmV79lZ5 z*QJRDI}jJWJa>LPGgNco-NT}60gyS{a6J$@;F?^M;FETkvlG zzV5(Fg>O}f8$pXM%ZSVo) z-`a*PY+Jbl_7&tCtd0y}>qVs7v;28*47GG4)Tzs2S!{o^0iMgQ&HdBGmOseY&w@Ko z9o`?HOzRk1Izz4XOIfDk-#WDgZ{HuMZ`gNO&%8Mu z`pZqyd~RYa-DRuc)rwcTNva_uyK)q>Dq*k`LBVwynG2kbeJ&Z%)<+T}TlqjEaTwUH zlOZ2AP>q?qsNu|0G^t;~KUJ@w_2IpVp<{pj`W!g5b$9F{IJI@|@z1mOZvFK27hizS zc^eBLHE})5lu8`QMy&^@wk)^HMtJDdiIH4;9&wb9FXoQs5$j~5 z0_T>A(GOg@h-3Ng-*U$edW_4)3f4TB7(3*rOHv2}E#ee~bjJpTXf0W(C}L4bH^h=F@ZQRWxd&V1XR_=eG zyjhj5>og(Bwuqmo<~zzKj^>jmCu)RLC#6)pK3-W{x?QfUt4N(x)=PL!lQJoo*K3f~ z$tUH8CEe(|lsiG#g!xmeG)&9s@lD-C%5xiBBZL;1n!vFxSiz7M|m%yRYdZ{Ij;Hvb04I z7+6?d0r>*LO}}xmM0&2%lrWrJ;G|7g7sX?;i=2({z7| z@rUjS*DTo_aQ3$^tQqblIh6PB(=H|4xov{eQl`EKUFb diff --git a/examples/bar.cpp b/examples/bar.cpp deleted file mode 100644 index 86423ad..0000000 --- a/examples/bar.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#define _USE_MATH_DEFINES - -#include -#include -#include "../matplotlibcpp.h" -namespace plt = matplotlibcpp; - -int main(int argc, char **argv) { - std::vector test_data; - for (int i = 0; i < 20; i++) { - test_data.push_back(i); - } - - plt::bar(test_data); - plt::show(); - - return (0); -} diff --git a/examples/bar.png b/examples/bar.png deleted file mode 100644 index be6af0fa449d932fd42ca9cadd8a83851e52d488..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11952 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 uITLK#^nu+e;34w -#include -#include "../matplotlibcpp.h" - -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; 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%0AEFGg;{EZPhaF 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 PVaZA -#include -#include "../matplotlibcpp.h" - -using namespace std; -namespace plt = matplotlibcpp; - -int main() -{ - // Prepare data - int ncols = 500, nrows = 300; - std::vector z(ncols * nrows); - for (int j=0; j - -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::contour(x, y, z); - plt::show(); -} diff --git a/examples/fill.cpp b/examples/fill.cpp deleted file mode 100644 index 6059b47..0000000 --- a/examples/fill.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#define _USE_MATH_DEFINES -#include "../matplotlibcpp.h" -#include - -using namespace std; -namespace plt = matplotlibcpp; - -// Example fill plot taken from: -// https://matplotlib.org/gallery/misc/fill_spiral.html -int main() { - // Prepare data. - vector theta; - for (double d = 0; d < 8 * M_PI; d += 0.1) - theta.push_back(d); - - const int a = 1; - const double b = 0.2; - - for (double dt = 0; dt < 2 * M_PI; dt += M_PI/2.0) { - vector x1, y1, x2, y2; - for (double th : theta) { - x1.push_back( a*cos(th + dt) * exp(b*th) ); - y1.push_back( a*sin(th + dt) * exp(b*th) ); - - x2.push_back( a*cos(th + dt + M_PI/4.0) * exp(b*th) ); - y2.push_back( a*sin(th + dt + M_PI/4.0) * exp(b*th) ); - } - - x1.insert(x1.end(), x2.rbegin(), x2.rend()); - y1.insert(y1.end(), y2.rbegin(), y2.rend()); - - plt::fill(x1, y1, {}); - } - plt::show(); -} diff --git a/examples/fill.png b/examples/fill.png deleted file mode 100644 index aa1fc0db3665bb4e38800974b85b238318851341..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62995 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 G{eJ)oR^-kA diff --git a/examples/fill_between.png b/examples/fill_between.png deleted file mode 100644 index a199423bdf0c0cea0010ffdfd0bf995395893683..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24970 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 -#include - -using namespace std; -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 < n; ++i) { - x.at(i) = i * i; - y.at(i) = sin(2 * M_PI * i / 360.0); - z.at(i) = log(i); - } - - // Prepare keywords to pass to PolyCollection. See - // https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.fill_between.html - std::map keywords; - keywords["alpha"] = "0.4"; - keywords["color"] = "grey"; - keywords["hatch"] = "-"; - - plt::fill_between(x, y, z, keywords); - plt::show(); -} diff --git a/examples/imshow.cpp b/examples/imshow.cpp deleted file mode 100644 index b11661e..0000000 --- a/examples/imshow.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#define _USE_MATH_DEFINES -#include -#include -#include "../matplotlibcpp.h" - -using namespace std; -namespace plt = matplotlibcpp; - -int main() -{ - // Prepare data - int ncols = 500, nrows = 300; - std::vector z(ncols * nrows); - for (int j=0; j - -namespace plt = matplotlibcpp; - -int main() -{ - std::vector x, y, z; - double theta, r; - double z_inc = 4.0/99.0; double theta_inc = (8.0 * M_PI)/99.0; - - for (double i = 0; i < 100; i += 1) { - theta = -4.0 * M_PI + theta_inc*i; - z.push_back(-2.0 + z_inc*i); - r = z[i]*z[i] + 1; - x.push_back(r * sin(theta)); - y.push_back(r * cos(theta)); - } - - std::map keywords; - keywords.insert(std::pair("label", "parametric curve") ); - - plt::plot3(x, y, z, keywords); - plt::xlabel("x label"); - plt::ylabel("y label"); - plt::set_zlabel("z label"); // set_zlabel rather than just zlabel, in accordance with the Axes3D method - plt::legend(); - plt::show(); -} diff --git a/examples/lines3d.png b/examples/lines3d.png deleted file mode 100644 index 7a0c478a0a598d36abb24b2f1d458d65316a60e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76500 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

>5!r2&I7XwI;6E?zG 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 diff --git a/examples/modern.cpp b/examples/modern.cpp deleted file mode 100644 index 871ef2b..0000000 --- a/examples/modern.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#define _USE_MATH_DEFINES -#include -#include "../matplotlibcpp.h" - -using namespace std; -namespace plt = matplotlibcpp; - -int main() -{ - // plot(y) - the x-coordinates are implicitly set to [0,1,...,n) - //plt::plot({1,2,3,4}); - - // Prepare data for parametric plot. - int n = 5000; // number of data points - vector x(n),y(n); - for(int i=0; i$>H}O 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 -#include "../matplotlibcpp.h" - -namespace plt = matplotlibcpp; - - -using namespace matplotlibcpp; -using namespace std; - -int main() -{ - // Prepare data. - int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i 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(); -} \ No newline at end of file diff --git a/examples/quiver.png b/examples/quiver.png deleted file mode 100644 index 9d7be1eec0f554fbd57490d5d83b3e93debd7c95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39752 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 -#include - -namespace plt = matplotlibcpp; - -int main() -{ - const int n = 20; - std::vector> matrix; - - for (int i = 0; i < n; ++i) { - std::vector row; - for (int j = 0; j < n; ++j) { - if (i == j) - row.push_back(-2); - else if (j == i - 1 || j == i + 1) - row.push_back(1); - else - row.push_back(0); - } - matrix.push_back(row); - } - - plt::spy(matrix, 5, {{"marker", "o"}}); - plt::show(); - - return 0; -} diff --git a/examples/subplot.cpp b/examples/subplot.cpp deleted file mode 100644 index bee322e..0000000 --- a/examples/subplot.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#define _USE_MATH_DEFINES -#include -#include "../matplotlibcpp.h" - -using namespace std; -namespace plt = matplotlibcpp; - -int main() -{ - // Prepare data - int n = 500; - 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 = 500; - std::vector x(n), u(n), v(n), w(n); - for(int i=0; i - -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); - plt::show(); -} diff --git a/examples/surface.png b/examples/surface.png deleted file mode 100644 index 6fc5fc76ba92343fee46f0951487a2463404ba24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106199 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 z 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�JR2!IvjUdLn*#_snfCTdZ!O=Gk8W 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 -#include "../matplotlibcpp.h" -#include - -namespace plt = matplotlibcpp; - -void update_window(const double x, const double y, const double t, - std::vector &xt, std::vector &yt) -{ - const double target_length = 300; - const double half_win = (target_length/(2.*sqrt(1.+t*t))); - - xt[0] = x - half_win; - xt[1] = x + half_win; - yt[0] = y - half_win*t; - yt[1] = y + half_win*t; -} - - -int main() -{ - size_t n = 1000; - std::vector x, y; - - const double w = 0.05; - const double a = n/2; - - for (size_t i=0; i xt(2), yt(2); - - plt::title("Tangent of a sine curve"); - plt::xlim(x.front(), x.back()); - plt::ylim(-a, a); - plt::axis("equal"); - - // Plot sin once and for all. - plt::named_plot("sin", x, y); - - // Prepare plotting the tangent. - plt::Plot plot("tangent"); - - plt::legend(); - - for (size_t i=0; i -#include "../matplotlibcpp.h" -#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::show(); -} - diff --git a/examples/xkcd.png b/examples/xkcd.png deleted file mode 100644 index c285e3d84464cc0b82425cbb2992caf24010dacc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79452 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
  • VYJc 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 diff --git a/matplotlibcpp.h b/include/matplotlibcpp.h similarity index 100% rename from matplotlibcpp.h rename to include/matplotlibcpp.h diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..f2a569e --- /dev/null +++ b/run.sh @@ -0,0 +1,16 @@ +# Check if the build directory exists +if [ -d "build" ]; then + echo "Removing existing build directory..." + rm -rf build +fi + +# Create a new build directory and navigate into it +mkdir build && cd build + +# Run CMake and make based on the selected build type +cmake -DPython3_EXECUTABLE=$(which python) .. + +make + +# Run the executable +./minimal \ No newline at end of file From d6fd8428b4f1d2cf51f6a66d40851654f08f9256 Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Thu, 28 Mar 2024 16:33:33 -0400 Subject: [PATCH 2/7] added 3d features --- .vscode/settings.json | 49 + CMakeLists.txt | 6 + examples/animated_3d.cpp | 115 ++ include/matplotlibcpp.h | 3089 +++++++++++++++++++++++++++++++++++++- run.sh | 3 +- 5 files changed, 3259 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 examples/animated_3d.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5c494d5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,49 @@ +{ + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "chrono": "cpp", + "complex": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "string": "cpp", + "string_view": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "stdexcept": "cpp", + "typeinfo": "cpp", + "bit": "cpp" + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index b22c5b8..908b2a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,10 +15,16 @@ include_directories(include/) # add executable add_executable(minimal examples/minimal.cpp) +add_executable(animated_3d examples/animated_3d.cpp) # link python and numpy target_link_libraries(minimal PRIVATE ${PYTHON_LIBRARIES} Python3::NumPy +) +target_link_libraries(animated_3d + PRIVATE + ${PYTHON_LIBRARIES} + Python3::NumPy ) \ No newline at end of file diff --git a/examples/animated_3d.cpp b/examples/animated_3d.cpp new file mode 100644 index 0000000..254b24b --- /dev/null +++ b/examples/animated_3d.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include "matplotlibcpp.h" +#include +#include + +namespace plt = matplotlibcpp; + +double fx(double x, double y) +{ + return -(pow(x, 2) + pow(y, 2)); +} + +double dfx(double x, double y) +{ + return -2.0*x; +} + +double dfy(double x, double y) +{ + return -2.0*y; +} + +double plane(double x, double y, double x0, double y0) +{ + return dfx(x0, y0)*(x - x0) + dfy(x0, y0)*(y - y0) + fx(x0, y0); +} + +std::map>> Tangent(double c, double x0, double y0) +{ + double m0 = x0 - c, m1 = x0 + c; + double n0 = y0 - c, n1 = y0 + c; + int o = 60; + + double dM = (m1 - m0)/(o - 1); + double dN = (n1 - n0)/(o - 1); + + std::map>> result; + std::vector tx, ty, tz; + + double rx, ry; + + for(int i = 0; i < o; ++i){ + tx.clear(); + ty.clear(); + tz.clear(); + rx = m0 + i*dM; + for(int j = 0; j < o; ++j){ + ry = n0 + j*dM; + tx.push_back(rx); + ty.push_back(ry); + tz.push_back(plane(rx, ry, x0, y0)); + } + result["x"].push_back(tx); + result["y"].push_back(ty); + result["z"].push_back(tz); + } + return result; +} + +int main() +{ + PyObject * ax = plt::chart(111); + plt::Clear3DChart(ax); + + int n = 60; + double t0 = -4.0, t1 = 4.0; + double dT = (t1 - t0)/(n - 1); + + std::vector> x, y, z; + std::vector tx, ty, tz; + + double rx, ry; + + for(int i = 0; i < n; ++i){ + tx.clear(); + ty.clear(); + tz.clear(); + rx = t0 + i*dT; + for(int j = 0; j < n; ++j){ + ry = t0 + j*dT; + tx.push_back(rx); + ty.push_back(ry); + tz.push_back(fx(rx, ry)); + } + x.push_back(tx); + y.push_back(ty); + z.push_back(tz); + } + + double Px = -3.5, Py = -3.5; + double learning = 0.15; + + std::map>> gd; + + for(int i = 0; i < 100; ++i){ + plt::Clear3DChart(ax); + gd = Tangent(2, Px, Py); + + plt::surface3D(ax, x, y, z, "red", 0.9); + plt::surface3D(ax, gd["x"], gd["y"], gd["z"], "green", 0.9); + + Px = Px + learning*dfx(Px, Py); + Py = Py + learning*dfy(Px, Py); + + plt::pause(0.5); + } + + + plt::show(); + + return 0; +} \ No newline at end of file diff --git a/include/matplotlibcpp.h b/include/matplotlibcpp.h index d95d46a..0adc313 100644 --- a/include/matplotlibcpp.h +++ b/include/matplotlibcpp.h @@ -1,3 +1,3017 @@ +// #pragma once + +// // Python headers must be included before any system headers, since +// // they define _POSIX_C_SOURCE +// #include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include // requires c++11 support +// #include +// #include // std::stod + +// #ifndef WITHOUT_NUMPY +// # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +// # include + +// # 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 +// #endif // WITHOUT_NUMPY + +// #if PY_MAJOR_VERSION >= 3 +// # define PyString_FromString PyUnicode_FromString +// # define PyInt_FromLong PyLong_FromLong +// # define PyString_FromString PyUnicode_FromString +// #endif + + +// namespace matplotlibcpp { +// namespace detail { + +// static std::string s_backend; + +// struct _interpreter { +// PyObject *pymod; +// 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 + +// void *import_numpy() { +// import_array(); // initialize C-API +// return NULL; +// } + +// # else + +// void import_numpy() { +// import_array(); // initialize C-API +// } + +// # endif +// #endif + +// _interpreter() { + +// // optional but recommended +// #if PY_MAJOR_VERSION >= 3 +// wchar_t name[] = L"plotting"; +// #else +// char name[] = "plotting"; +// #endif +// Py_SetProgramName(name); +// Py_Initialize(); + +// 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)); +// #else +// PySys_SetArgv(argc, (char **)(argv)); +// #endif + +// #ifndef WITHOUT_NUMPY +// 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 * mpl_toolkitsmod; +// PyObject * axis3dmod; +// 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!"); } +// } + + +// 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"); +// #endif +// 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; +// } + +// 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()); + +// PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); +// PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "xy", xy); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, str); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); + +// return res; +// } + +// PyObject * chart(int place) +// { +// PyObject * drawObject=PyObject_GetAttrString(detail::_interpreter::get().pymod,"subplot"); +// PyObject * args = PyTuple_New(1); +// PyObject * kwargs =PyDict_New(); +// PyTuple_SetItem(args,0,PyLong_FromLong(place)); +// PyDict_SetItemString(kwargs,"projection",PyUnicode_FromString("3d")); +// PyObject * thePlot=PyObject_Call(drawObject,args,kwargs); +// return thePlot; +// } + +// 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; +// } + + +// 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())}; + +// PyArrayObject *varray = +// (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); + +// 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]; +// } + +// 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; +// } + +// #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(); + +// // using numpy arrays +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// // construct positional args +// PyObject* args = PyTuple_New(2); +// PyTuple_SetItem(args, 0, xarray); +// PyTuple_SetItem(args, 1, yarray); + +// // construct keyword args +// PyObject* kwargs = PyDict_New(); +// for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) +// { +// PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); +// } + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// if(res) Py_DECREF(res); + +// return res; +// } + +// // 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 + +// 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()); + +// detail::_interpreter::get(); + +// // using numpy arrays +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// // construct positional args +// PyObject* args = PyTuple_New(2); +// PyTuple_SetItem(args, 0, xarray); +// PyTuple_SetItem(args, 1, yarray); + +// // construct keyword args +// PyObject* kwargs = PyDict_New(); +// for (std::map::const_iterator it = +// keywords.begin(); it != keywords.end(); ++it) { +// PyDict_SetItemString(kwargs, it->first.c_str(), +// PyString_FromString(it->second.c_str())); +// } + +// PyObject* res = PyObject_Call( +// detail::_interpreter::get().s_python_function_stem, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// if (res) +// Py_DECREF(res); + +// return res; +// } + +// template< typename Numeric > +// bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) +// { +// assert(x.size() == y.size()); + +// detail::_interpreter::get(); + +// // using numpy arrays +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// // construct positional args +// PyObject* args = PyTuple_New(2); +// PyTuple_SetItem(args, 0, xarray); +// PyTuple_SetItem(args, 1, yarray); + +// // construct keyword args +// PyObject* kwargs = PyDict_New(); +// for (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(detail::_interpreter::get().s_python_function_fill, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if (res) Py_DECREF(res); + +// return res; +// } + +// 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); + +// Py_DECREF(plot_args); +// Py_DECREF(kwargs); +// if (res) +// Py_DECREF(res); + +// return res; +// } + +// 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(); + +// PyObject* yarray = detail::get_array(y); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); +// PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); +// PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); +// PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); + +// 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; +// } + +// #ifndef WITHOUT_NUMPY +// namespace detail { + +// 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); +// } + +// } // 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); +// } + +// 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); +// } + +// #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 + +// 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(); + +// assert(x.size() == y.size()); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// 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); + +// 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 = {}) +// { +// 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); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); +// PyDict_SetItemString(kwargs, "c", colors_array); + +// 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); + +// 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(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(); + +// // 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)); +// } + +// // take care of the remaining keywords +// for (const auto& it : keywords) +// { +// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); +// } + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); + +// return res; +// } + +// template +// bool boxplot(const std::vector& data, +// const std::map & keywords = {}) +// { +// detail::_interpreter::get(); + +// PyObject* vector = detail::get_array(data); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, vector); + +// PyObject* kwargs = PyDict_New(); +// for (const auto& it : keywords) +// { +// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); +// } + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); + +// 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())); +// } + +// 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 = {}) +// { +// 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; +// } + +// 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* 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); + +// 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()); + +// 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); + +// return res; +// } + +// template +// bool semilogx(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_semilogx, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(res); + +// return res; +// } + +// template +// bool semilogy(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_semilogy, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(res); + +// return res; +// } + +// template +// bool loglog(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_loglog, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(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()); + +// 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); + +// PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); + +// if (res) +// Py_DECREF(res); +// else +// throw std::runtime_error("Call to errorbar() failed."); + +// return res; +// } + +// template +// bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(2); + +// PyTuple_SetItem(plot_args, 0, yarray); +// PyTuple_SetItem(plot_args, 1, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// 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); +// } + +// template +// void text(Numeric x, Numeric y, const std::string& s = "") +// { +// 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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); +// if(!res) throw std::runtime_error("Call to text() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// 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."); + +// detail::_interpreter::get(); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, mappable); + +// 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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); +// if(!res) throw std::runtime_error("Call to colorbar() failed."); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// Py_DECREF(res); +// } + + +// inline long figure(long number = -1) +// { +// detail::_interpreter::get(); + +// 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); + +// // Make sure interpreter is initialised +// 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); +// Py_DECREF(args); +// } + +// 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); + +// Py_DECREF(num); +// Py_DECREF(res); + +// return figureNumber; +// } + +// inline bool fignum_exists(long number) +// { +// detail::_interpreter::get(); + +// 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."); + +// bool ret = PyObject_IsTrue(res); +// Py_DECREF(res); +// Py_DECREF(args); + +// return ret; +// } + +// inline void figure_size(size_t w, size_t h) +// { +// detail::_interpreter::get(); + +// 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)); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "figsize", size); +// PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, +// detail::_interpreter::get().s_python_empty_tuple, kwargs); + +// Py_DECREF(kwargs); + +// if(!res) throw std::runtime_error("Call to figure_size() failed."); +// Py_DECREF(res); +// } + +// inline void legend() +// { +// 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."); + +// Py_DECREF(res); +// } + +// inline void legend(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())); +// } + +// 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(kwargs); +// Py_DECREF(res); +// } + +// template +// inline void set_aspect(Numeric ratio) +// { +// detail::_interpreter::get(); + +// 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 *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); +// } + +// 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* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, list); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); +// if(!res) throw std::runtime_error("Call to ylim() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// template +// 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* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, list); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); +// if(!res) throw std::runtime_error("Call to xlim() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + + +// inline 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."); + +// Py_DECREF(res); + +// PyObject* left = PyTuple_GetItem(res,0); +// PyObject* right = PyTuple_GetItem(res,1); +// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; +// } + + +// inline std::array ylim() +// { +// PyObject* args = PyTuple_New(0); +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + +// if(!res) throw std::runtime_error("Call to ylim() failed."); + +// Py_DECREF(res); + +// PyObject* left = PyTuple_GetItem(res,0); +// PyObject* right = PyTuple_GetItem(res,1); +// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; +// } + +// template +// inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +// { +// assert(labels.size() == 0 || ticks.size() == labels.size()); + +// detail::_interpreter::get(); + +// // using numpy array +// PyObject* ticksarray = detail::get_array(ticks); + +// 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); +// } + +// // 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(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"); + +// Py_DECREF(res); +// } + +// template +// inline void xticks(const std::vector &ticks, const std::map& keywords) +// { +// xticks(ticks, {}, keywords); +// } + +// template +// inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +// { +// assert(labels.size() == 0 || ticks.size() == labels.size()); + +// detail::_interpreter::get(); + +// // using numpy array +// PyObject* ticksarray = detail::get_array(ticks); + +// 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); +// } + +// // 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(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"); + +// Py_DECREF(res); +// } + +// template +// inline void yticks(const std::vector &ticks, const std::map& keywords) +// { +// yticks(ticks, {}, keywords); +// } + +// template inline void margins(Numeric margin) +// { +// // construct positional args +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); + +// PyObject* res = +// PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); +// if (!res) +// throw std::runtime_error("Call to margins() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// 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_CallObject(detail::_interpreter::get().s_python_function_margins, args); +// if (!res) +// throw std::runtime_error("Call to margins() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + + +// inline void tick_params(const std::map& keywords, const std::string axis = "both") +// { +// detail::_interpreter::get(); + +// // construct positional args +// PyObject* args; +// args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); +// } + + +// 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"); + +// Py_DECREF(res); +// } + +// inline void subplot(long nrows, long ncols, long plot_number) +// { +// detail::_interpreter::get(); + +// // construct positional args +// PyObject* args = PyTuple_New(3); +// PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); +// PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); +// PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); +// if(!res) throw std::runtime_error("Call to subplot() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) +// { +// detail::_interpreter::get(); + +// PyObject* shape = PyTuple_New(2); +// PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); +// PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); + +// PyObject* loc = PyTuple_New(2); +// PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); +// PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); + +// 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_subplot2grid, args); +// if(!res) throw std::runtime_error("Call to subplot2grid() failed."); + +// Py_DECREF(shape); +// Py_DECREF(loc); +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void title(const std::string &titlestr, const std::map &keywords = {}) +// { +// detail::_interpreter::get(); + +// 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* 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 suptitle(const std::string &suptitlestr, const std::map &keywords = {}) +// { +// detail::_interpreter::get(); + +// PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pysuptitlestr); + +// 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(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); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); +// if(!res) throw std::runtime_error("Call to title() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) +// { +// detail::_interpreter::get(); + +// // 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)); + +// // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); +// } + +// inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) +// { +// detail::_interpreter::get(); + +// // 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)); + +// // 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(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)); + +// // 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(); + +// PyObject* pystr = PyString_FromString(str.c_str()); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pystr); + +// 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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); +// if(!res) throw std::runtime_error("Call to xlabel() failed."); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// Py_DECREF(res); +// } + +// inline void ylabel(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); + +// 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(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 set_zlabel(const std::string &str, const std::map& keywords = {}) +// { +// 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) { +// 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* pystr = PyString_FromString(str.c_str()); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pystr); + +// 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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); +// if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); +// Py_INCREF(zlabel); + +// PyObject *res = PyObject_Call(zlabel, args, kwargs); +// if (!res) throw std::runtime_error("Call to set_zlabel() failed."); +// Py_DECREF(zlabel); + +// Py_DECREF(ax); +// Py_DECREF(args); +// Py_DECREF(kwargs); +// if (res) Py_DECREF(res); +// } + +// inline void grid(bool flag) +// { +// detail::_interpreter::get(); + +// PyObject* pyflag = flag ? Py_True : Py_False; +// Py_INCREF(pyflag); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pyflag); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); +// if(!res) throw std::runtime_error("Call to grid() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void show(const bool block = true) +// { +// 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."); + +// Py_DECREF(res); +// } + +// inline void close() +// { +// detail::_interpreter::get(); + +// 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); + +// 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); + +// if (!res) throw std::runtime_error("Call to draw() failed."); + +// Py_DECREF(res); +// } + +// template +// inline void pause(Numeric interval) +// { +// detail::_interpreter::get(); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); +// if(!res) throw std::runtime_error("Call to pause() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void save(const std::string& filename, const int dpi=0) +// { +// detail::_interpreter::get(); + +// PyObject* pyfilename = PyString_FromString(filename.c_str()); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pyfilename); + +// PyObject* kwargs = PyDict_New(); + +// if(dpi > 0) +// { +// PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); +// } + +// 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(args); +// Py_DECREF(kwargs); +// Py_DECREF(res); +// } + +// 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 * 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); + +// if (!res) throw std::runtime_error("Call to clf() failed."); + +// Py_DECREF(res); +// } + +// inline void cla() { +// detail::_interpreter::get(); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, +// detail::_interpreter::get().s_python_empty_tuple); + +// if (!res) +// throw std::runtime_error("Call to cla() failed."); + +// Py_DECREF(res); +// } + +// inline void ion() { +// detail::_interpreter::get(); + +// PyObject *res = PyObject_CallObject( +// detail::_interpreter::get().s_python_function_ion, +// detail::_interpreter::get().s_python_empty_tuple); + +// if (!res) throw std::runtime_error("Call to ion() failed."); + +// Py_DECREF(res); +// } + +// inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) +// { +// detail::_interpreter::get(); + +// PyObject *args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); + +// // 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_ginput, args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(args); +// if (!res) throw std::runtime_error("Call to ginput() 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); + +// return out; +// } + +// // Actually, is there any reason not to call this automatically for every plot? +// inline void tight_layout() { +// detail::_interpreter::get(); + +// PyObject *res = PyObject_CallObject( +// detail::_interpreter::get().s_python_function_tight_layout, +// detail::_interpreter::get().s_python_empty_tuple); + +// if (!res) throw std::runtime_error("Call to tight_layout() failed."); + +// Py_DECREF(res); +// } + +// // Support for variadic plot() and initializer lists: + +// namespace detail { + +// template +// using is_function = typename std::is_function>>::type; + +// template +// struct is_callable_impl; + +// template +// struct is_callable_impl +// { +// typedef is_function type; +// }; // a non-object is callable iff it is a function + +// 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; +// }; + +// template +// struct plot_impl { }; + +// 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::distance; +// using std::begin; +// using std::end; + +// auto xs = distance(begin(x), end(x)); +// auto ys = distance(begin(y), end(y)); +// assert(xs == ys && "x and y data must have the same number of elements!"); + +// PyObject* xlist = PyList_New(xs); +// PyObject* ylist = PyList_New(ys); +// PyObject* pystring = PyString_FromString(format.c_str()); + +// auto itx = begin(x), ity = begin(y); +// for(size_t i = 0; i < xs; ++i) { +// PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); +// PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); +// } + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xlist); +// PyTuple_SetItem(plot_args, 1, ylist); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(res); + +// return res; +// } +// }; + +// template<> +// struct plot_impl +// { +// 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...); +// } + +// /* +// * 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); +// } + +// inline bool plot(const std::vector& y, const std::string& format = "") { +// return plot(y,format); +// } + +// inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { +// return plot(x,y,keywords); +// } + +// /* +// * 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(); + +// assert(x.size() == y.size()); + +// PyObject* kwargs = PyDict_New(); +// if(name != "") +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); + +// if(res) +// { +// line= PyList_GetItem(res, 0); + +// if(line) +// set_data_fct = PyObject_GetAttrString(line,"set_data"); +// else +// Py_DECREF(line); +// Py_DECREF(res); +// } +// } + +// // 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) +// { +// 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; +// } + +// // clears the plot but keep it available +// bool clear() { +// return update(std::vector(), std::vector()); +// } + +// // definitely remove this line +// void remove() { +// 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(); +// } + +// ~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; +// }; + +// } // end namespace matplotlibcpp #pragma once // Python headers must be included before any system headers, since @@ -46,6 +3060,7 @@ namespace detail { static std::string s_backend; struct _interpreter { + PyObject* pymod; PyObject* s_python_function_arrow; PyObject *s_python_function_show; PyObject *s_python_function_close; @@ -212,10 +3227,37 @@ struct _interpreter { - PyObject* pymod = PyImport_Import(pyplotname); + pymod = PyImport_Import(pyplotname); Py_DECREF(pyplotname); if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } + PyObject * mpl_toolkitsmod; + PyObject * axis3dmod; + 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!"); } + } + + + + + + + + + + + + s_python_colormap = PyImport_Import(cmname); Py_DECREF(cmname); if (!s_python_colormap) { throw std::runtime_error("Error loading module matplotlib.cm!"); } @@ -331,6 +3373,24 @@ inline bool annotate(std::string annotation, double x, double y) return res; } +PyObject * chart(int place) +{ + PyObject * drawObject = PyObject_GetAttrString(detail::_interpreter::get().pymod, "subplot"); + PyObject * args = PyTuple_New(1); + PyObject * kwargs = PyDict_New(); + PyTuple_SetItem(args, 0, PyLong_FromLong(place)); + PyDict_SetItemString(kwargs, "projection", PyUnicode_FromString("3d")); + PyObject * thePlot = PyObject_Call(drawObject, args, kwargs); + return thePlot; +} + +inline void Clear3DChart(PyObject * ax) +{ + PyObject * eraser = PyObject_GetAttrString(ax, "cla"); + PyObject * args = PyTuple_New(0); + PyObject_CallObject(eraser, args); +} + namespace detail { #ifndef WITHOUT_NUMPY @@ -473,6 +3533,31 @@ bool plot(const std::vector &x, const std::vector &y, const st // TODO - it should be possible to make this work by implementing // a non-numpy alternative for `detail::get_2darray()`. #ifndef WITHOUT_NUMPY +template +void surface3D(PyObject * ax, + const std::vector<::std::vector> &x, + const std::vector<::std::vector> &y, + const std::vector<::std::vector> &z, + std::string color, + double linewidth) +{ + PyObject * X = detail::get_2darray(x); + PyObject * Y = detail::get_2darray(y); + PyObject * Z = detail::get_2darray(z); + + PyObject * args = PyTuple_New(3); + PyObject * kwargs = PyDict_New(); + PyTuple_SetItem(args, 0, X); + PyTuple_SetItem(args, 1, Y); + PyTuple_SetItem(args, 2, Z); + PyDict_SetItemString(kwargs, "color", PyUnicode_FromString(color.c_str())); + PyDict_SetItemString(kwargs, "linewidth", PyLong_FromLong(linewidth)); + + + PyObject * thePlot = PyObject_GetAttrString(ax, "plot_surface"); + PyObject_Call(thePlot, args, kwargs); +} + template void plot_surface(const std::vector<::std::vector> &x, const std::vector<::std::vector> &y, @@ -2983,4 +6068,4 @@ class Plot PyObject* set_data_fct = nullptr; }; -} // end namespace matplotlibcpp +} // end namespace matplotlibcpp \ No newline at end of file diff --git a/run.sh b/run.sh index f2a569e..c01cba6 100644 --- a/run.sh +++ b/run.sh @@ -13,4 +13,5 @@ cmake -DPython3_EXECUTABLE=$(which python) .. make # Run the executable -./minimal \ No newline at end of file +./minimal +./animated_3d \ No newline at end of file From 0dd80dd4826292f222d504495d4f1bff38f5bd46 Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Thu, 28 Mar 2024 17:34:10 -0400 Subject: [PATCH 3/7] made it a library --- CMakeLists.txt | 62 +- README.md | 30 +- cmake/matplotlibcpp_lib-config.cmake | 7 + examples/CMakeLists.txt | 18 + run.sh => examples/run_examples.sh | 0 install.sh | 19 + install/include/matplotlibcpp.h | 6071 +++++++++++++++++ .../lib/cmake/matplotlibcpp_lib-config.cmake | 7 + .../cmake/matplotlibcpp_lib-noconfig.cmake | 19 + install/lib/cmake/matplotlibcpp_lib.cmake | 101 + install/src/matplotlibcpp.cpp | 1 + src/matplotlibcpp.cpp | 1 + 12 files changed, 6321 insertions(+), 15 deletions(-) create mode 100644 cmake/matplotlibcpp_lib-config.cmake create mode 100644 examples/CMakeLists.txt rename run.sh => examples/run_examples.sh (100%) create mode 100644 install.sh create mode 100644 install/include/matplotlibcpp.h create mode 100644 install/lib/cmake/matplotlibcpp_lib-config.cmake create mode 100644 install/lib/cmake/matplotlibcpp_lib-noconfig.cmake create mode 100644 install/lib/cmake/matplotlibcpp_lib.cmake create mode 100644 install/src/matplotlibcpp.cpp create mode 100644 src/matplotlibcpp.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 908b2a3..5f8b9b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,30 +1,64 @@ # CMakeLists.txt cmake_minimum_required(VERSION 3.15) -project("example" LANGUAGES CXX) +project(matplotlibcpp LANGUAGES CXX) +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install) # comment this if you want to install in /usr/local +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") # neede for include(...) set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings") # bypass dev warnings +# -------------------------------------------------------------------------- # +# Build C++ library # +# -------------------------------------------------------------------------- # + +set(LIBRARY_NAME matplotlibcpp_lib) + # find python libraries find_package(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) find_package(PythonLibs 3.0 REQUIRED) include_directories(${PYTHON3_INCLUDE_DIRS} ${NumPy_INCLUDE_DIRS}) -# populate matplotlib repository -include_directories(include/) +# add library +add_library(${LIBRARY_NAME} SHARED + src/matplotlibcpp.cpp +) -# add executable -add_executable(minimal examples/minimal.cpp) -add_executable(animated_3d examples/animated_3d.cpp) +target_include_directories(${LIBRARY_NAME} PUBLIC + $ + $ + $ + $ +) -# link python and numpy -target_link_libraries(minimal - PRIVATE +target_link_libraries(${LIBRARY_NAME} ${PYTHON_LIBRARIES} Python3::NumPy ) -target_link_libraries(animated_3d - PRIVATE - ${PYTHON_LIBRARIES} - Python3::NumPy -) \ No newline at end of file + +set_target_properties( + ${LIBRARY_NAME} + PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO +) + +# -------------------------------------------------------------------------- # +# Install # +# -------------------------------------------------------------------------- # +install(TARGETS ${LIBRARY_NAME} + EXPORT ${LIBRARY_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) + +install(EXPORT ${LIBRARY_NAME} + FILE ${LIBRARY_NAME}.cmake + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cmake) + +install(FILES cmake/${LIBRARY_NAME}-config.cmake + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cmake) + +install(DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_PREFIX}/include) + +install(DIRECTORY src/ + DESTINATION ${CMAKE_INSTALL_PREFIX}/src) \ No newline at end of file diff --git a/README.md b/README.md index 32fc63e..ce69211 100644 --- a/README.md +++ b/README.md @@ -3,5 +3,33 @@ This is a fork of the original [matplotlib-cpp](https://github.com/lava/matplotlib-cpp). Its characterized for being: - minimal: Just the necessary files. -- cmake-friendly: Compile from cmake! +- library: Install it as a library for usage in other projects. - extended 3D rendering: Copied from [this video](https://www.youtube.com/watch?v=NOZDyFmWDtw) + +## Installation + +Build and install the library with `install.sh` as follows: + +```bash +source install_cpp.sh +``` + +## Usage + +If you have successfully built the project, you are ready to start using the installed library. By default matplotlibcpp will be installed as a shared library in `/path/to/matplotlibcpp/install/`, and thereby, it can easily be linked to other projects using CMakeLists.txt as follows: + +```cmake +set(CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/../install/lib/cmake) + +find_package(matplotlibcpp_lib REQUIRED) + +add_executable(my_excutable my_executable.cpp) +target_link_libraries(my_executable matplotlibcpp_lib) + +``` + +For exemplary files that showcase how to use the library can be found in [the examples folder](examples/). You can run an example by running: + +```bash +bash examples/run_examples.sh +``` diff --git a/cmake/matplotlibcpp_lib-config.cmake b/cmake/matplotlibcpp_lib-config.cmake new file mode 100644 index 0000000..3a32769 --- /dev/null +++ b/cmake/matplotlibcpp_lib-config.cmake @@ -0,0 +1,7 @@ +include(CMakeFindDependencyMacro) + +find_dependency(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) +find_dependency(PythonLibs 3.0 REQUIRED) + +get_filename_component(SELF_DIR ${CMAKE_CURRENT_LIST_DIR} PATH) +include(${SELF_DIR}/cmake/matplotlibcpp_lib.cmake) \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..44ebdb8 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.14) +project(matplotlibcpp_examples) + +# set path to motplit_lib installation( comment if installed in /usr/local) +set(CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/../install/lib/cmake) + +# to avoid PCL warnings +set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings") # bypass PCL warnings + +# find motplit_lib package +find_package(matplotlibcpp_lib REQUIRED) + +# add executable and link libraries +add_executable(animated_3d animated_3d.cpp) +target_link_libraries(animated_3d matplotlibcpp_lib) + +add_executable(minimal minimal.cpp) +target_link_libraries(minimal matplotlibcpp_lib) \ No newline at end of file diff --git a/run.sh b/examples/run_examples.sh similarity index 100% rename from run.sh rename to examples/run_examples.sh diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..a72e2bc --- /dev/null +++ b/install.sh @@ -0,0 +1,19 @@ +# Check if the build directory exists +if [ -d "build" ]; then + echo "Removing existing build directory..." + rm -rf build +fi + +# Create a new build directory and navigate into it +mkdir build && cd build + +# Run CMake and make based on the selected build type +cmake -DPython3_EXECUTABLE=$(which python) -DCMAKE_INSTALL_PREFIX=$pwd/install .. +make + +# Install the executable +make install + +# # Run the executable +# ./minimal +# ./animated_3d \ No newline at end of file diff --git a/install/include/matplotlibcpp.h b/install/include/matplotlibcpp.h new file mode 100644 index 0000000..0adc313 --- /dev/null +++ b/install/include/matplotlibcpp.h @@ -0,0 +1,6071 @@ +// #pragma once + +// // Python headers must be included before any system headers, since +// // they define _POSIX_C_SOURCE +// #include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include // requires c++11 support +// #include +// #include // std::stod + +// #ifndef WITHOUT_NUMPY +// # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +// # include + +// # 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 +// #endif // WITHOUT_NUMPY + +// #if PY_MAJOR_VERSION >= 3 +// # define PyString_FromString PyUnicode_FromString +// # define PyInt_FromLong PyLong_FromLong +// # define PyString_FromString PyUnicode_FromString +// #endif + + +// namespace matplotlibcpp { +// namespace detail { + +// static std::string s_backend; + +// struct _interpreter { +// PyObject *pymod; +// 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 + +// void *import_numpy() { +// import_array(); // initialize C-API +// return NULL; +// } + +// # else + +// void import_numpy() { +// import_array(); // initialize C-API +// } + +// # endif +// #endif + +// _interpreter() { + +// // optional but recommended +// #if PY_MAJOR_VERSION >= 3 +// wchar_t name[] = L"plotting"; +// #else +// char name[] = "plotting"; +// #endif +// Py_SetProgramName(name); +// Py_Initialize(); + +// 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)); +// #else +// PySys_SetArgv(argc, (char **)(argv)); +// #endif + +// #ifndef WITHOUT_NUMPY +// 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 * mpl_toolkitsmod; +// PyObject * axis3dmod; +// 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!"); } +// } + + +// 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"); +// #endif +// 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; +// } + +// 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()); + +// PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); +// PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "xy", xy); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, str); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); + +// return res; +// } + +// PyObject * chart(int place) +// { +// PyObject * drawObject=PyObject_GetAttrString(detail::_interpreter::get().pymod,"subplot"); +// PyObject * args = PyTuple_New(1); +// PyObject * kwargs =PyDict_New(); +// PyTuple_SetItem(args,0,PyLong_FromLong(place)); +// PyDict_SetItemString(kwargs,"projection",PyUnicode_FromString("3d")); +// PyObject * thePlot=PyObject_Call(drawObject,args,kwargs); +// return thePlot; +// } + +// 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; +// } + + +// 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())}; + +// PyArrayObject *varray = +// (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); + +// 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]; +// } + +// 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; +// } + +// #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(); + +// // using numpy arrays +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// // construct positional args +// PyObject* args = PyTuple_New(2); +// PyTuple_SetItem(args, 0, xarray); +// PyTuple_SetItem(args, 1, yarray); + +// // construct keyword args +// PyObject* kwargs = PyDict_New(); +// for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) +// { +// PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); +// } + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// if(res) Py_DECREF(res); + +// return res; +// } + +// // 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 + +// 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()); + +// detail::_interpreter::get(); + +// // using numpy arrays +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// // construct positional args +// PyObject* args = PyTuple_New(2); +// PyTuple_SetItem(args, 0, xarray); +// PyTuple_SetItem(args, 1, yarray); + +// // construct keyword args +// PyObject* kwargs = PyDict_New(); +// for (std::map::const_iterator it = +// keywords.begin(); it != keywords.end(); ++it) { +// PyDict_SetItemString(kwargs, it->first.c_str(), +// PyString_FromString(it->second.c_str())); +// } + +// PyObject* res = PyObject_Call( +// detail::_interpreter::get().s_python_function_stem, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// if (res) +// Py_DECREF(res); + +// return res; +// } + +// template< typename Numeric > +// bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) +// { +// assert(x.size() == y.size()); + +// detail::_interpreter::get(); + +// // using numpy arrays +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// // construct positional args +// PyObject* args = PyTuple_New(2); +// PyTuple_SetItem(args, 0, xarray); +// PyTuple_SetItem(args, 1, yarray); + +// // construct keyword args +// PyObject* kwargs = PyDict_New(); +// for (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(detail::_interpreter::get().s_python_function_fill, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if (res) Py_DECREF(res); + +// return res; +// } + +// 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); + +// Py_DECREF(plot_args); +// Py_DECREF(kwargs); +// if (res) +// Py_DECREF(res); + +// return res; +// } + +// 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(); + +// PyObject* yarray = detail::get_array(y); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); +// PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); +// PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); +// PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); + +// 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; +// } + +// #ifndef WITHOUT_NUMPY +// namespace detail { + +// 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); +// } + +// } // 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); +// } + +// 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); +// } + +// #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 + +// 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(); + +// assert(x.size() == y.size()); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// 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); + +// 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 = {}) +// { +// 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); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); +// PyDict_SetItemString(kwargs, "c", colors_array); + +// 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); + +// 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(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(); + +// // 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)); +// } + +// // take care of the remaining keywords +// for (const auto& it : keywords) +// { +// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); +// } + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); + +// return res; +// } + +// template +// bool boxplot(const std::vector& data, +// const std::map & keywords = {}) +// { +// detail::_interpreter::get(); + +// PyObject* vector = detail::get_array(data); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, vector); + +// PyObject* kwargs = PyDict_New(); +// for (const auto& it : keywords) +// { +// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); +// } + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); + +// 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())); +// } + +// 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 = {}) +// { +// 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; +// } + +// 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* 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); + +// 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()); + +// 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); + +// return res; +// } + +// template +// bool semilogx(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_semilogx, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(res); + +// return res; +// } + +// template +// bool semilogy(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_semilogy, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(res); + +// return res; +// } + +// template +// bool loglog(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_loglog, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(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()); + +// 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); + +// PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); + +// if (res) +// Py_DECREF(res); +// else +// throw std::runtime_error("Call to errorbar() failed."); + +// return res; +// } + +// template +// bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(2); + +// PyTuple_SetItem(plot_args, 0, yarray); +// PyTuple_SetItem(plot_args, 1, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +// { +// detail::_interpreter::get(); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); +// if (res) Py_DECREF(res); + +// return res; +// } + +// template +// 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); +// } + +// template +// void text(Numeric x, Numeric y, const std::string& s = "") +// { +// 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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); +// if(!res) throw std::runtime_error("Call to text() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// 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."); + +// detail::_interpreter::get(); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, mappable); + +// 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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); +// if(!res) throw std::runtime_error("Call to colorbar() failed."); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// Py_DECREF(res); +// } + + +// inline long figure(long number = -1) +// { +// detail::_interpreter::get(); + +// 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); + +// // Make sure interpreter is initialised +// 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); +// Py_DECREF(args); +// } + +// 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); + +// Py_DECREF(num); +// Py_DECREF(res); + +// return figureNumber; +// } + +// inline bool fignum_exists(long number) +// { +// detail::_interpreter::get(); + +// 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."); + +// bool ret = PyObject_IsTrue(res); +// Py_DECREF(res); +// Py_DECREF(args); + +// return ret; +// } + +// inline void figure_size(size_t w, size_t h) +// { +// detail::_interpreter::get(); + +// 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)); + +// PyObject* kwargs = PyDict_New(); +// PyDict_SetItemString(kwargs, "figsize", size); +// PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, +// detail::_interpreter::get().s_python_empty_tuple, kwargs); + +// Py_DECREF(kwargs); + +// if(!res) throw std::runtime_error("Call to figure_size() failed."); +// Py_DECREF(res); +// } + +// inline void legend() +// { +// 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."); + +// Py_DECREF(res); +// } + +// inline void legend(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())); +// } + +// 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(kwargs); +// Py_DECREF(res); +// } + +// template +// inline void set_aspect(Numeric ratio) +// { +// detail::_interpreter::get(); + +// 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 *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); +// } + +// 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* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, list); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); +// if(!res) throw std::runtime_error("Call to ylim() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// template +// 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* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, list); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); +// if(!res) throw std::runtime_error("Call to xlim() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + + +// inline 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."); + +// Py_DECREF(res); + +// PyObject* left = PyTuple_GetItem(res,0); +// PyObject* right = PyTuple_GetItem(res,1); +// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; +// } + + +// inline std::array ylim() +// { +// PyObject* args = PyTuple_New(0); +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + +// if(!res) throw std::runtime_error("Call to ylim() failed."); + +// Py_DECREF(res); + +// PyObject* left = PyTuple_GetItem(res,0); +// PyObject* right = PyTuple_GetItem(res,1); +// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; +// } + +// template +// inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +// { +// assert(labels.size() == 0 || ticks.size() == labels.size()); + +// detail::_interpreter::get(); + +// // using numpy array +// PyObject* ticksarray = detail::get_array(ticks); + +// 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); +// } + +// // 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(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"); + +// Py_DECREF(res); +// } + +// template +// inline void xticks(const std::vector &ticks, const std::map& keywords) +// { +// xticks(ticks, {}, keywords); +// } + +// template +// inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +// { +// assert(labels.size() == 0 || ticks.size() == labels.size()); + +// detail::_interpreter::get(); + +// // using numpy array +// PyObject* ticksarray = detail::get_array(ticks); + +// 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); +// } + +// // 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(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"); + +// Py_DECREF(res); +// } + +// template +// inline void yticks(const std::vector &ticks, const std::map& keywords) +// { +// yticks(ticks, {}, keywords); +// } + +// template inline void margins(Numeric margin) +// { +// // construct positional args +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); + +// PyObject* res = +// PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); +// if (!res) +// throw std::runtime_error("Call to margins() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// 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_CallObject(detail::_interpreter::get().s_python_function_margins, args); +// if (!res) +// throw std::runtime_error("Call to margins() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + + +// inline void tick_params(const std::map& keywords, const std::string axis = "both") +// { +// detail::_interpreter::get(); + +// // construct positional args +// PyObject* args; +// args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); +// } + + +// 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"); + +// Py_DECREF(res); +// } + +// inline void subplot(long nrows, long ncols, long plot_number) +// { +// detail::_interpreter::get(); + +// // construct positional args +// PyObject* args = PyTuple_New(3); +// PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); +// PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); +// PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); +// if(!res) throw std::runtime_error("Call to subplot() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) +// { +// detail::_interpreter::get(); + +// PyObject* shape = PyTuple_New(2); +// PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); +// PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); + +// PyObject* loc = PyTuple_New(2); +// PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); +// PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); + +// 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_subplot2grid, args); +// if(!res) throw std::runtime_error("Call to subplot2grid() failed."); + +// Py_DECREF(shape); +// Py_DECREF(loc); +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void title(const std::string &titlestr, const std::map &keywords = {}) +// { +// detail::_interpreter::get(); + +// 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* 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 suptitle(const std::string &suptitlestr, const std::map &keywords = {}) +// { +// detail::_interpreter::get(); + +// PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pysuptitlestr); + +// 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(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); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); +// if(!res) throw std::runtime_error("Call to title() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) +// { +// detail::_interpreter::get(); + +// // 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)); + +// // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); + +// Py_DECREF(args); +// Py_DECREF(kwargs); + +// if(res) Py_DECREF(res); +// } + +// inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) +// { +// detail::_interpreter::get(); + +// // 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)); + +// // 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(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)); + +// // 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(); + +// PyObject* pystr = PyString_FromString(str.c_str()); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pystr); + +// 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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); +// if(!res) throw std::runtime_error("Call to xlabel() failed."); + +// Py_DECREF(args); +// Py_DECREF(kwargs); +// Py_DECREF(res); +// } + +// inline void ylabel(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); + +// 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(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 set_zlabel(const std::string &str, const std::map& keywords = {}) +// { +// 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) { +// 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* pystr = PyString_FromString(str.c_str()); +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pystr); + +// 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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); +// if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); +// Py_INCREF(zlabel); + +// PyObject *res = PyObject_Call(zlabel, args, kwargs); +// if (!res) throw std::runtime_error("Call to set_zlabel() failed."); +// Py_DECREF(zlabel); + +// Py_DECREF(ax); +// Py_DECREF(args); +// Py_DECREF(kwargs); +// if (res) Py_DECREF(res); +// } + +// inline void grid(bool flag) +// { +// detail::_interpreter::get(); + +// PyObject* pyflag = flag ? Py_True : Py_False; +// Py_INCREF(pyflag); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pyflag); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); +// if(!res) throw std::runtime_error("Call to grid() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void show(const bool block = true) +// { +// 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."); + +// Py_DECREF(res); +// } + +// inline void close() +// { +// detail::_interpreter::get(); + +// 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); + +// 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); + +// if (!res) throw std::runtime_error("Call to draw() failed."); + +// Py_DECREF(res); +// } + +// template +// inline void pause(Numeric interval) +// { +// detail::_interpreter::get(); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); +// if(!res) throw std::runtime_error("Call to pause() failed."); + +// Py_DECREF(args); +// Py_DECREF(res); +// } + +// inline void save(const std::string& filename, const int dpi=0) +// { +// detail::_interpreter::get(); + +// PyObject* pyfilename = PyString_FromString(filename.c_str()); + +// PyObject* args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, pyfilename); + +// PyObject* kwargs = PyDict_New(); + +// if(dpi > 0) +// { +// PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); +// } + +// 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(args); +// Py_DECREF(kwargs); +// Py_DECREF(res); +// } + +// 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 * 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); + +// if (!res) throw std::runtime_error("Call to clf() failed."); + +// Py_DECREF(res); +// } + +// inline void cla() { +// detail::_interpreter::get(); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, +// detail::_interpreter::get().s_python_empty_tuple); + +// if (!res) +// throw std::runtime_error("Call to cla() failed."); + +// Py_DECREF(res); +// } + +// inline void ion() { +// detail::_interpreter::get(); + +// PyObject *res = PyObject_CallObject( +// detail::_interpreter::get().s_python_function_ion, +// detail::_interpreter::get().s_python_empty_tuple); + +// if (!res) throw std::runtime_error("Call to ion() failed."); + +// Py_DECREF(res); +// } + +// inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) +// { +// detail::_interpreter::get(); + +// PyObject *args = PyTuple_New(1); +// PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); + +// // 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_ginput, args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(args); +// if (!res) throw std::runtime_error("Call to ginput() 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); + +// return out; +// } + +// // Actually, is there any reason not to call this automatically for every plot? +// inline void tight_layout() { +// detail::_interpreter::get(); + +// PyObject *res = PyObject_CallObject( +// detail::_interpreter::get().s_python_function_tight_layout, +// detail::_interpreter::get().s_python_empty_tuple); + +// if (!res) throw std::runtime_error("Call to tight_layout() failed."); + +// Py_DECREF(res); +// } + +// // Support for variadic plot() and initializer lists: + +// namespace detail { + +// template +// using is_function = typename std::is_function>>::type; + +// template +// struct is_callable_impl; + +// template +// struct is_callable_impl +// { +// typedef is_function type; +// }; // a non-object is callable iff it is a function + +// 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; +// }; + +// template +// struct plot_impl { }; + +// 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::distance; +// using std::begin; +// using std::end; + +// auto xs = distance(begin(x), end(x)); +// auto ys = distance(begin(y), end(y)); +// assert(xs == ys && "x and y data must have the same number of elements!"); + +// PyObject* xlist = PyList_New(xs); +// PyObject* ylist = PyList_New(ys); +// PyObject* pystring = PyString_FromString(format.c_str()); + +// auto itx = begin(x), ity = begin(y); +// for(size_t i = 0; i < xs; ++i) { +// PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); +// PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); +// } + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xlist); +// PyTuple_SetItem(plot_args, 1, ylist); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + +// Py_DECREF(plot_args); +// if(res) Py_DECREF(res); + +// return res; +// } +// }; + +// template<> +// struct plot_impl +// { +// 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...); +// } + +// /* +// * 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); +// } + +// inline bool plot(const std::vector& y, const std::string& format = "") { +// return plot(y,format); +// } + +// inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { +// return plot(x,y,keywords); +// } + +// /* +// * 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(); + +// assert(x.size() == y.size()); + +// PyObject* kwargs = PyDict_New(); +// if(name != "") +// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + +// PyObject* xarray = detail::get_array(x); +// PyObject* yarray = detail::get_array(y); + +// PyObject* pystring = PyString_FromString(format.c_str()); + +// PyObject* plot_args = PyTuple_New(3); +// PyTuple_SetItem(plot_args, 0, xarray); +// PyTuple_SetItem(plot_args, 1, yarray); +// PyTuple_SetItem(plot_args, 2, pystring); + +// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + +// Py_DECREF(kwargs); +// Py_DECREF(plot_args); + +// if(res) +// { +// line= PyList_GetItem(res, 0); + +// if(line) +// set_data_fct = PyObject_GetAttrString(line,"set_data"); +// else +// Py_DECREF(line); +// Py_DECREF(res); +// } +// } + +// // 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) +// { +// 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; +// } + +// // clears the plot but keep it available +// bool clear() { +// return update(std::vector(), std::vector()); +// } + +// // definitely remove this line +// void remove() { +// 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(); +// } + +// ~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; +// }; + +// } // end namespace matplotlibcpp +#pragma once + +// Python headers must be included before any system headers, since +// they define _POSIX_C_SOURCE +#include + +#include +#include +#include +#include +#include +#include +#include +#include // requires c++11 support +#include +#include // std::stod + +#ifndef WITHOUT_NUMPY +# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +# include + +# 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 +#endif // WITHOUT_NUMPY + +#if PY_MAJOR_VERSION >= 3 +# define PyString_FromString PyUnicode_FromString +# define PyInt_FromLong PyLong_FromLong +# define PyString_FromString PyUnicode_FromString +#endif + + +namespace matplotlibcpp { +namespace detail { + +static std::string s_backend; + +struct _interpreter { + PyObject* pymod; + 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 + + void *import_numpy() { + import_array(); // initialize C-API + return NULL; + } + +# else + + void import_numpy() { + import_array(); // initialize C-API + } + +# endif +#endif + + _interpreter() { + + // optional but recommended +#if PY_MAJOR_VERSION >= 3 + wchar_t name[] = L"plotting"; +#else + char name[] = "plotting"; +#endif + Py_SetProgramName(name); + Py_Initialize(); + + 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)); +#else + PySys_SetArgv(argc, (char **)(argv)); +#endif + +#ifndef WITHOUT_NUMPY + 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()); + } + + + + pymod = PyImport_Import(pyplotname); + Py_DECREF(pyplotname); + if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } + + PyObject * mpl_toolkitsmod; + PyObject * axis3dmod; + 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!"); } + } + + + + + + + + + + + + + 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"); +#endif + 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; +} + +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()); + + PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); + PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "xy", xy); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, str); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + + if(res) Py_DECREF(res); + + return res; +} + +PyObject * chart(int place) +{ + PyObject * drawObject = PyObject_GetAttrString(detail::_interpreter::get().pymod, "subplot"); + PyObject * args = PyTuple_New(1); + PyObject * kwargs = PyDict_New(); + PyTuple_SetItem(args, 0, PyLong_FromLong(place)); + PyDict_SetItemString(kwargs, "projection", PyUnicode_FromString("3d")); + PyObject * thePlot = PyObject_Call(drawObject, args, kwargs); + return thePlot; +} + +inline void Clear3DChart(PyObject * ax) +{ + PyObject * eraser = PyObject_GetAttrString(ax, "cla"); + PyObject * args = PyTuple_New(0); + PyObject_CallObject(eraser, args); +} + +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; +} + + +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())}; + + PyArrayObject *varray = + (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); + + 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]; + } + + 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; +} + +#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(); + + // using numpy arrays + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + // construct positional args + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + if(res) Py_DECREF(res); + + return res; +} + +// TODO - it should be possible to make this work by implementing +// a non-numpy alternative for `detail::get_2darray()`. +#ifndef WITHOUT_NUMPY +template +void surface3D(PyObject * ax, + const std::vector<::std::vector> &x, + const std::vector<::std::vector> &y, + const std::vector<::std::vector> &z, + std::string color, + double linewidth) +{ + PyObject * X = detail::get_2darray(x); + PyObject * Y = detail::get_2darray(y); + PyObject * Z = detail::get_2darray(z); + + PyObject * args = PyTuple_New(3); + PyObject * kwargs = PyDict_New(); + PyTuple_SetItem(args, 0, X); + PyTuple_SetItem(args, 1, Y); + PyTuple_SetItem(args, 2, Z); + PyDict_SetItemString(kwargs, "color", PyUnicode_FromString(color.c_str())); + PyDict_SetItemString(kwargs, "linewidth", PyLong_FromLong(linewidth)); + + + PyObject * thePlot = PyObject_GetAttrString(ax, "plot_surface"); + PyObject_Call(thePlot, args, kwargs); +} + +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 + +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()); + + detail::_interpreter::get(); + + // using numpy arrays + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + // construct positional args + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = + keywords.begin(); it != keywords.end(); ++it) { + PyDict_SetItemString(kwargs, it->first.c_str(), + PyString_FromString(it->second.c_str())); + } + + PyObject* res = PyObject_Call( + detail::_interpreter::get().s_python_function_stem, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; +} + +template< typename Numeric > +bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) +{ + assert(x.size() == y.size()); + + detail::_interpreter::get(); + + // using numpy arrays + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + // construct positional args + PyObject* args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (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(detail::_interpreter::get().s_python_function_fill, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + + if (res) Py_DECREF(res); + + return res; +} + +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); + + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; +} + +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(); + + PyObject* yarray = detail::get_array(y); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); + PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); + PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); + PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); + + 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; +} + +#ifndef WITHOUT_NUMPY +namespace detail { + +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); +} + +} // 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); +} + +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); +} + +#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 + +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(); + + assert(x.size() == y.size()); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + 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); + + 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 = {}) + { + 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); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); + PyDict_SetItemString(kwargs, "c", colors_array); + + 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); + + 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(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(); + + // 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)); + } + + // take care of the remaining keywords + for (const auto& it : keywords) + { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + + if(res) Py_DECREF(res); + + return res; +} + +template +bool boxplot(const std::vector& data, + const std::map & keywords = {}) +{ + detail::_interpreter::get(); + + PyObject* vector = detail::get_array(data); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, vector); + + PyObject* kwargs = PyDict_New(); + for (const auto& it : keywords) + { + PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + } + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + + if(res) Py_DECREF(res); + + 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())); + } + + 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 = {}) +{ + 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; +} + +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* 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); + + 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()); + + 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); + + return res; +} + +template +bool semilogx(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_semilogx, plot_args); + + Py_DECREF(plot_args); + if(res) Py_DECREF(res); + + return res; +} + +template +bool semilogy(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_semilogy, plot_args); + + Py_DECREF(plot_args); + if(res) Py_DECREF(res); + + return res; +} + +template +bool loglog(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_loglog, plot_args); + + Py_DECREF(plot_args); + if(res) Py_DECREF(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()); + + 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); + + PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + + if (res) + Py_DECREF(res); + else + throw std::runtime_error("Call to errorbar() failed."); + + return res; +} + +template +bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") +{ + detail::_interpreter::get(); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + PyObject* yarray = detail::get_array(y); + + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(2); + + PyTuple_SetItem(plot_args, 0, yarray); + PyTuple_SetItem(plot_args, 1, pystring); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +{ + detail::_interpreter::get(); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +{ + detail::_interpreter::get(); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +{ + detail::_interpreter::get(); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +{ + detail::_interpreter::get(); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) Py_DECREF(res); + + return res; +} + +template +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); +} + +template +void text(Numeric x, Numeric y, const std::string& s = "") +{ + 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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); + if(!res) throw std::runtime_error("Call to text() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +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."); + + detail::_interpreter::get(); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, mappable); + + 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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); + if(!res) throw std::runtime_error("Call to colorbar() failed."); + + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); +} + + +inline long figure(long number = -1) +{ + detail::_interpreter::get(); + + 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); + + // Make sure interpreter is initialised + 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); + Py_DECREF(args); + } + + 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); + + Py_DECREF(num); + Py_DECREF(res); + + return figureNumber; +} + +inline bool fignum_exists(long number) +{ + detail::_interpreter::get(); + + 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."); + + bool ret = PyObject_IsTrue(res); + Py_DECREF(res); + Py_DECREF(args); + + return ret; +} + +inline void figure_size(size_t w, size_t h) +{ + detail::_interpreter::get(); + + 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)); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "figsize", size); + PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple, kwargs); + + Py_DECREF(kwargs); + + if(!res) throw std::runtime_error("Call to figure_size() failed."); + Py_DECREF(res); +} + +inline void legend() +{ + 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."); + + Py_DECREF(res); +} + +inline void legend(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())); + } + + 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(kwargs); + Py_DECREF(res); +} + +template +inline void set_aspect(Numeric ratio) +{ + detail::_interpreter::get(); + + 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 *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); +} + +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* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, list); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + if(!res) throw std::runtime_error("Call to ylim() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +template +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* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, list); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + if(!res) throw std::runtime_error("Call to xlim() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + + +inline 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."); + + Py_DECREF(res); + + PyObject* left = PyTuple_GetItem(res,0); + PyObject* right = PyTuple_GetItem(res,1); + return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; +} + + +inline std::array ylim() +{ + PyObject* args = PyTuple_New(0); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + + if(!res) throw std::runtime_error("Call to ylim() failed."); + + Py_DECREF(res); + + PyObject* left = PyTuple_GetItem(res,0); + PyObject* right = PyTuple_GetItem(res,1); + return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; +} + +template +inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +{ + assert(labels.size() == 0 || ticks.size() == labels.size()); + + detail::_interpreter::get(); + + // using numpy array + PyObject* ticksarray = detail::get_array(ticks); + + 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); + } + + // 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(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"); + + Py_DECREF(res); +} + +template +inline void xticks(const std::vector &ticks, const std::map& keywords) +{ + xticks(ticks, {}, keywords); +} + +template +inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) +{ + assert(labels.size() == 0 || ticks.size() == labels.size()); + + detail::_interpreter::get(); + + // using numpy array + PyObject* ticksarray = detail::get_array(ticks); + + 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); + } + + // 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(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"); + + Py_DECREF(res); +} + +template +inline void yticks(const std::vector &ticks, const std::map& keywords) +{ + yticks(ticks, {}, keywords); +} + +template inline void margins(Numeric margin) +{ + // construct positional args + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); + + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); + if (!res) + throw std::runtime_error("Call to margins() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +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_CallObject(detail::_interpreter::get().s_python_function_margins, args); + if (!res) + throw std::runtime_error("Call to margins() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + + +inline void tick_params(const std::map& keywords, const std::string axis = "both") +{ + detail::_interpreter::get(); + + // construct positional args + PyObject* args; + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); + } + + + 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"); + + Py_DECREF(res); +} + +inline void subplot(long nrows, long ncols, long plot_number) +{ + detail::_interpreter::get(); + + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); + PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); + if(!res) throw std::runtime_error("Call to subplot() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) +{ + detail::_interpreter::get(); + + PyObject* shape = PyTuple_New(2); + PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); + PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); + + PyObject* loc = PyTuple_New(2); + PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); + PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); + + 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_subplot2grid, args); + if(!res) throw std::runtime_error("Call to subplot2grid() failed."); + + Py_DECREF(shape); + Py_DECREF(loc); + Py_DECREF(args); + Py_DECREF(res); +} + +inline void title(const std::string &titlestr, const std::map &keywords = {}) +{ + detail::_interpreter::get(); + + 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* 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 suptitle(const std::string &suptitlestr, const std::map &keywords = {}) +{ + detail::_interpreter::get(); + + PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pysuptitlestr); + + 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(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); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); + if(!res) throw std::runtime_error("Call to title() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) +{ + detail::_interpreter::get(); + + // 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)); + + // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); + + if(res) Py_DECREF(res); +} + +inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) +{ + detail::_interpreter::get(); + + // 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)); + + // 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(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)); + + // 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(); + + PyObject* pystr = PyString_FromString(str.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); + + 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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); + if(!res) throw std::runtime_error("Call to xlabel() failed."); + + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); +} + +inline void ylabel(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); + + 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(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 set_zlabel(const std::string &str, const std::map& keywords = {}) +{ + 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) { + 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* pystr = PyString_FromString(str.c_str()); + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); + + 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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); + if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); + Py_INCREF(zlabel); + + PyObject *res = PyObject_Call(zlabel, args, kwargs); + if (!res) throw std::runtime_error("Call to set_zlabel() failed."); + Py_DECREF(zlabel); + + Py_DECREF(ax); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); +} + +inline void grid(bool flag) +{ + detail::_interpreter::get(); + + PyObject* pyflag = flag ? Py_True : Py_False; + Py_INCREF(pyflag); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyflag); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); + if(!res) throw std::runtime_error("Call to grid() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +inline void show(const bool block = true) +{ + 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."); + + Py_DECREF(res); +} + +inline void close() +{ + detail::_interpreter::get(); + + 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); + + 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); + + if (!res) throw std::runtime_error("Call to draw() failed."); + + Py_DECREF(res); +} + +template +inline void pause(Numeric interval) +{ + detail::_interpreter::get(); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); + if(!res) throw std::runtime_error("Call to pause() failed."); + + Py_DECREF(args); + Py_DECREF(res); +} + +inline void save(const std::string& filename, const int dpi=0) +{ + detail::_interpreter::get(); + + PyObject* pyfilename = PyString_FromString(filename.c_str()); + + PyObject* args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyfilename); + + PyObject* kwargs = PyDict_New(); + + if(dpi > 0) + { + PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); + } + + 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(args); + Py_DECREF(kwargs); + Py_DECREF(res); +} + +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 * 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); + + if (!res) throw std::runtime_error("Call to clf() failed."); + + Py_DECREF(res); +} + +inline void cla() { + detail::_interpreter::get(); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, + detail::_interpreter::get().s_python_empty_tuple); + + if (!res) + throw std::runtime_error("Call to cla() failed."); + + Py_DECREF(res); +} + +inline void ion() { + detail::_interpreter::get(); + + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_ion, + detail::_interpreter::get().s_python_empty_tuple); + + if (!res) throw std::runtime_error("Call to ion() failed."); + + Py_DECREF(res); +} + +inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) +{ + detail::_interpreter::get(); + + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); + + // 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_ginput, args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(args); + if (!res) throw std::runtime_error("Call to ginput() 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); + + return out; +} + +// Actually, is there any reason not to call this automatically for every plot? +inline void tight_layout() { + detail::_interpreter::get(); + + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_tight_layout, + detail::_interpreter::get().s_python_empty_tuple); + + if (!res) throw std::runtime_error("Call to tight_layout() failed."); + + Py_DECREF(res); +} + +// Support for variadic plot() and initializer lists: + +namespace detail { + +template +using is_function = typename std::is_function>>::type; + +template +struct is_callable_impl; + +template +struct is_callable_impl +{ + typedef is_function type; +}; // a non-object is callable iff it is a function + +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; +}; + +template +struct plot_impl { }; + +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::distance; + using std::begin; + using std::end; + + auto xs = distance(begin(x), end(x)); + auto ys = distance(begin(y), end(y)); + assert(xs == ys && "x and y data must have the same number of elements!"); + + PyObject* xlist = PyList_New(xs); + PyObject* ylist = PyList_New(ys); + PyObject* pystring = PyString_FromString(format.c_str()); + + auto itx = begin(x), ity = begin(y); + for(size_t i = 0; i < xs; ++i) { + PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); + PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); + } + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xlist); + PyTuple_SetItem(plot_args, 1, ylist); + PyTuple_SetItem(plot_args, 2, pystring); + + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + + Py_DECREF(plot_args); + if(res) Py_DECREF(res); + + return res; + } +}; + +template<> +struct plot_impl +{ + 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...); +} + +/* + * 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); +} + +inline bool plot(const std::vector& y, const std::string& format = "") { + return plot(y,format); +} + +inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { + return plot(x,y,keywords); +} + +/* + * 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(); + + assert(x.size() == y.size()); + + PyObject* kwargs = PyDict_New(); + if(name != "") + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + + PyObject* pystring = PyString_FromString(format.c_str()); + + PyObject* plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); + + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + + Py_DECREF(kwargs); + Py_DECREF(plot_args); + + if(res) + { + line= PyList_GetItem(res, 0); + + if(line) + set_data_fct = PyObject_GetAttrString(line,"set_data"); + else + Py_DECREF(line); + Py_DECREF(res); + } + } + + // 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) + { + 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; + } + + // clears the plot but keep it available + bool clear() { + return update(std::vector(), std::vector()); + } + + // definitely remove this line + void remove() { + 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(); + } + + ~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; +}; + +} // end namespace matplotlibcpp \ No newline at end of file diff --git a/install/lib/cmake/matplotlibcpp_lib-config.cmake b/install/lib/cmake/matplotlibcpp_lib-config.cmake new file mode 100644 index 0000000..3a32769 --- /dev/null +++ b/install/lib/cmake/matplotlibcpp_lib-config.cmake @@ -0,0 +1,7 @@ +include(CMakeFindDependencyMacro) + +find_dependency(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) +find_dependency(PythonLibs 3.0 REQUIRED) + +get_filename_component(SELF_DIR ${CMAKE_CURRENT_LIST_DIR} PATH) +include(${SELF_DIR}/cmake/matplotlibcpp_lib.cmake) \ No newline at end of file diff --git a/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake b/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake new file mode 100644 index 0000000..0d0d346 --- /dev/null +++ b/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "matplotlibcpp_lib" for configuration "" +set_property(TARGET matplotlibcpp_lib APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(matplotlibcpp_lib PROPERTIES + IMPORTED_LOCATION_NOCONFIG "/home/jonarriza96/mtpcpp/matplotlib-cpp/install/lib/libmatplotlibcpp_lib.so" + IMPORTED_SONAME_NOCONFIG "libmatplotlibcpp_lib.so" + ) + +list(APPEND _cmake_import_check_targets matplotlibcpp_lib ) +list(APPEND _cmake_import_check_files_for_matplotlibcpp_lib "/home/jonarriza96/mtpcpp/matplotlib-cpp/install/lib/libmatplotlibcpp_lib.so" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/install/lib/cmake/matplotlibcpp_lib.cmake b/install/lib/cmake/matplotlibcpp_lib.cmake new file mode 100644 index 0000000..664d29e --- /dev/null +++ b/install/lib/cmake/matplotlibcpp_lib.cmake @@ -0,0 +1,101 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.26) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS matplotlibcpp_lib) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# The installation prefix configured by this project. +set(_IMPORT_PREFIX "/home/jonarriza96/mtpcpp/matplotlib-cpp/install") + +# Create imported target matplotlibcpp_lib +add_library(matplotlibcpp_lib SHARED IMPORTED) + +set_target_properties(matplotlibcpp_lib PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "/home/jonarriza96/mtpcpp/matplotlib-cpp/install/include;/home/jonarriza96/mtpcpp/matplotlib-cpp/install/src" + INTERFACE_LINK_LIBRARIES "/usr/lib/x86_64-linux-gnu/libpython3.8.so;Python3::NumPy" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/matplotlibcpp_lib-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/install/src/matplotlibcpp.cpp b/install/src/matplotlibcpp.cpp new file mode 100644 index 0000000..e7914e1 --- /dev/null +++ b/install/src/matplotlibcpp.cpp @@ -0,0 +1 @@ +#include "matplotlibcpp.h" \ No newline at end of file diff --git a/src/matplotlibcpp.cpp b/src/matplotlibcpp.cpp new file mode 100644 index 0000000..e7914e1 --- /dev/null +++ b/src/matplotlibcpp.cpp @@ -0,0 +1 @@ +#include "matplotlibcpp.h" \ No newline at end of file From 13aee302b9010dbc0741ee7afc0e8d2213d668a8 Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Thu, 28 Mar 2024 17:35:46 -0400 Subject: [PATCH 4/7] Remove the now ignored directory "vscode" --- .vscode/settings.json | 49 ------------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5c494d5..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "files.associations": { - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "array": "cpp", - "atomic": "cpp", - "*.tcc": "cpp", - "chrono": "cpp", - "complex": "cpp", - "cstdint": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "map": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "random": "cpp", - "ratio": "cpp", - "string": "cpp", - "string_view": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "ostream": "cpp", - "stdexcept": "cpp", - "typeinfo": "cpp", - "bit": "cpp" - } -} From 46111bbe37750132a4685c618a3a3414f3d5efcc Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Thu, 28 Mar 2024 18:48:59 -0400 Subject: [PATCH 5/7] fixed intstallation things --- .gitignore | 3 ++- CMakeLists.txt | 2 +- README.md | 3 ++- install.sh | 12 +++++++++++- install/lib/cmake/matplotlibcpp_lib-noconfig.cmake | 4 ++-- install/lib/cmake/matplotlibcpp_lib.cmake | 4 ++-- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 355708e..6c30f59 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ *.sw* # CMake -build/ \ No newline at end of file +build/ +install/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f8b9b0..5ff53c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15) project(matplotlibcpp LANGUAGES CXX) -set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install) # comment this if you want to install in /usr/local +# set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install) # comment this if you want to install in /usr/local set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") # neede for include(...) set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings") # bypass dev warnings diff --git a/README.md b/README.md index ce69211..a8e88cd 100644 --- a/README.md +++ b/README.md @@ -31,5 +31,6 @@ target_link_libraries(my_executable matplotlibcpp_lib) For exemplary files that showcase how to use the library can be found in [the examples folder](examples/). You can run an example by running: ```bash -bash examples/run_examples.sh +cd examples +bash run_examples.sh ``` diff --git a/install.sh b/install.sh index a72e2bc..bde6bad 100644 --- a/install.sh +++ b/install.sh @@ -1,3 +1,13 @@ +# Set default install prefix +install_prefix="$PWD/install" + +# Check if an argument is provided +if [ -n "$1" ]; then + install_prefix="$1" + echo "Installing to custom directory: $install_prefix" +fi + + # Check if the build directory exists if [ -d "build" ]; then echo "Removing existing build directory..." @@ -8,7 +18,7 @@ fi mkdir build && cd build # Run CMake and make based on the selected build type -cmake -DPython3_EXECUTABLE=$(which python) -DCMAKE_INSTALL_PREFIX=$pwd/install .. +cmake -DPython3_EXECUTABLE=$(which python) -DCMAKE_INSTALL_PREFIX="$install_prefix" .. make # Install the executable diff --git a/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake b/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake index 0d0d346..4901355 100644 --- a/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake +++ b/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake @@ -8,12 +8,12 @@ set(CMAKE_IMPORT_FILE_VERSION 1) # Import target "matplotlibcpp_lib" for configuration "" set_property(TARGET matplotlibcpp_lib APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) set_target_properties(matplotlibcpp_lib PROPERTIES - IMPORTED_LOCATION_NOCONFIG "/home/jonarriza96/mtpcpp/matplotlib-cpp/install/lib/libmatplotlibcpp_lib.so" + IMPORTED_LOCATION_NOCONFIG "/home/jonarriza96/papor/external/matplotlibcpp/install/lib/libmatplotlibcpp_lib.so" IMPORTED_SONAME_NOCONFIG "libmatplotlibcpp_lib.so" ) list(APPEND _cmake_import_check_targets matplotlibcpp_lib ) -list(APPEND _cmake_import_check_files_for_matplotlibcpp_lib "/home/jonarriza96/mtpcpp/matplotlib-cpp/install/lib/libmatplotlibcpp_lib.so" ) +list(APPEND _cmake_import_check_files_for_matplotlibcpp_lib "/home/jonarriza96/papor/external/matplotlibcpp/install/lib/libmatplotlibcpp_lib.so" ) # Commands beyond this point should not need to know the version. set(CMAKE_IMPORT_FILE_VERSION) diff --git a/install/lib/cmake/matplotlibcpp_lib.cmake b/install/lib/cmake/matplotlibcpp_lib.cmake index 664d29e..221ed17 100644 --- a/install/lib/cmake/matplotlibcpp_lib.cmake +++ b/install/lib/cmake/matplotlibcpp_lib.cmake @@ -47,13 +47,13 @@ unset(_cmake_expected_targets) # The installation prefix configured by this project. -set(_IMPORT_PREFIX "/home/jonarriza96/mtpcpp/matplotlib-cpp/install") +set(_IMPORT_PREFIX "/home/jonarriza96/papor/external/matplotlibcpp/install") # Create imported target matplotlibcpp_lib add_library(matplotlibcpp_lib SHARED IMPORTED) set_target_properties(matplotlibcpp_lib PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "/home/jonarriza96/mtpcpp/matplotlib-cpp/install/include;/home/jonarriza96/mtpcpp/matplotlib-cpp/install/src" + INTERFACE_INCLUDE_DIRECTORIES "/home/jonarriza96/papor/external/matplotlibcpp/install/include;/home/jonarriza96/papor/external/matplotlibcpp/install/src" INTERFACE_LINK_LIBRARIES "/usr/lib/x86_64-linux-gnu/libpython3.8.so;Python3::NumPy" ) From f2cb606af6a713a77cc010ae034dee94e078526d Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Thu, 28 Mar 2024 18:50:01 -0400 Subject: [PATCH 6/7] removed cached folder --- install/include/matplotlibcpp.h | 6071 ----------------- .../lib/cmake/matplotlibcpp_lib-config.cmake | 7 - .../cmake/matplotlibcpp_lib-noconfig.cmake | 19 - install/lib/cmake/matplotlibcpp_lib.cmake | 101 - install/src/matplotlibcpp.cpp | 1 - 5 files changed, 6199 deletions(-) delete mode 100644 install/include/matplotlibcpp.h delete mode 100644 install/lib/cmake/matplotlibcpp_lib-config.cmake delete mode 100644 install/lib/cmake/matplotlibcpp_lib-noconfig.cmake delete mode 100644 install/lib/cmake/matplotlibcpp_lib.cmake delete mode 100644 install/src/matplotlibcpp.cpp diff --git a/install/include/matplotlibcpp.h b/install/include/matplotlibcpp.h deleted file mode 100644 index 0adc313..0000000 --- a/install/include/matplotlibcpp.h +++ /dev/null @@ -1,6071 +0,0 @@ -// #pragma once - -// // Python headers must be included before any system headers, since -// // they define _POSIX_C_SOURCE -// #include - -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include // requires c++11 support -// #include -// #include // std::stod - -// #ifndef WITHOUT_NUMPY -// # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -// # include - -// # 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 -// #endif // WITHOUT_NUMPY - -// #if PY_MAJOR_VERSION >= 3 -// # define PyString_FromString PyUnicode_FromString -// # define PyInt_FromLong PyLong_FromLong -// # define PyString_FromString PyUnicode_FromString -// #endif - - -// namespace matplotlibcpp { -// namespace detail { - -// static std::string s_backend; - -// struct _interpreter { -// PyObject *pymod; -// 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 - -// void *import_numpy() { -// import_array(); // initialize C-API -// return NULL; -// } - -// # else - -// void import_numpy() { -// import_array(); // initialize C-API -// } - -// # endif -// #endif - -// _interpreter() { - -// // optional but recommended -// #if PY_MAJOR_VERSION >= 3 -// wchar_t name[] = L"plotting"; -// #else -// char name[] = "plotting"; -// #endif -// Py_SetProgramName(name); -// Py_Initialize(); - -// 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)); -// #else -// PySys_SetArgv(argc, (char **)(argv)); -// #endif - -// #ifndef WITHOUT_NUMPY -// 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 * mpl_toolkitsmod; -// PyObject * axis3dmod; -// 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!"); } -// } - - -// 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"); -// #endif -// 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; -// } - -// 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()); - -// PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); -// PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "xy", xy); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, str); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); - -// return res; -// } - -// PyObject * chart(int place) -// { -// PyObject * drawObject=PyObject_GetAttrString(detail::_interpreter::get().pymod,"subplot"); -// PyObject * args = PyTuple_New(1); -// PyObject * kwargs =PyDict_New(); -// PyTuple_SetItem(args,0,PyLong_FromLong(place)); -// PyDict_SetItemString(kwargs,"projection",PyUnicode_FromString("3d")); -// PyObject * thePlot=PyObject_Call(drawObject,args,kwargs); -// return thePlot; -// } - -// 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; -// } - - -// 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())}; - -// PyArrayObject *varray = -// (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - -// 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]; -// } - -// 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; -// } - -// #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(); - -// // using numpy arrays -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// // construct positional args -// PyObject* args = PyTuple_New(2); -// PyTuple_SetItem(args, 0, xarray); -// PyTuple_SetItem(args, 1, yarray); - -// // construct keyword args -// PyObject* kwargs = PyDict_New(); -// for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) -// { -// PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); -// } - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// if(res) Py_DECREF(res); - -// return res; -// } - -// // 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 - -// 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()); - -// detail::_interpreter::get(); - -// // using numpy arrays -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// // construct positional args -// PyObject* args = PyTuple_New(2); -// PyTuple_SetItem(args, 0, xarray); -// PyTuple_SetItem(args, 1, yarray); - -// // construct keyword args -// PyObject* kwargs = PyDict_New(); -// for (std::map::const_iterator it = -// keywords.begin(); it != keywords.end(); ++it) { -// PyDict_SetItemString(kwargs, it->first.c_str(), -// PyString_FromString(it->second.c_str())); -// } - -// PyObject* res = PyObject_Call( -// detail::_interpreter::get().s_python_function_stem, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// if (res) -// Py_DECREF(res); - -// return res; -// } - -// template< typename Numeric > -// bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -// { -// assert(x.size() == y.size()); - -// detail::_interpreter::get(); - -// // using numpy arrays -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// // construct positional args -// PyObject* args = PyTuple_New(2); -// PyTuple_SetItem(args, 0, xarray); -// PyTuple_SetItem(args, 1, yarray); - -// // construct keyword args -// PyObject* kwargs = PyDict_New(); -// for (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(detail::_interpreter::get().s_python_function_fill, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if (res) Py_DECREF(res); - -// return res; -// } - -// 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); - -// Py_DECREF(plot_args); -// Py_DECREF(kwargs); -// if (res) -// Py_DECREF(res); - -// return res; -// } - -// 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(); - -// PyObject* yarray = detail::get_array(y); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); -// PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); -// PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); -// PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); - -// 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; -// } - -// #ifndef WITHOUT_NUMPY -// namespace detail { - -// 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); -// } - -// } // 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); -// } - -// 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); -// } - -// #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 - -// 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(); - -// assert(x.size() == y.size()); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// 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); - -// 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 = {}) -// { -// 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); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); -// PyDict_SetItemString(kwargs, "c", colors_array); - -// 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); - -// 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(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(); - -// // 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)); -// } - -// // take care of the remaining keywords -// for (const auto& it : keywords) -// { -// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); -// } - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); - -// return res; -// } - -// template -// bool boxplot(const std::vector& data, -// const std::map & keywords = {}) -// { -// detail::_interpreter::get(); - -// PyObject* vector = detail::get_array(data); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, vector); - -// PyObject* kwargs = PyDict_New(); -// for (const auto& it : keywords) -// { -// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); -// } - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); - -// 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())); -// } - -// 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 = {}) -// { -// 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; -// } - -// 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* 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); - -// 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()); - -// 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); - -// return res; -// } - -// template -// bool semilogx(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_semilogx, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(res); - -// return res; -// } - -// template -// bool semilogy(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_semilogy, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(res); - -// return res; -// } - -// template -// bool loglog(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_loglog, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(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()); - -// 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); - -// PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); - -// if (res) -// Py_DECREF(res); -// else -// throw std::runtime_error("Call to errorbar() failed."); - -// return res; -// } - -// template -// bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(2); - -// PyTuple_SetItem(plot_args, 0, yarray); -// PyTuple_SetItem(plot_args, 1, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// 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); -// } - -// template -// void text(Numeric x, Numeric y, const std::string& s = "") -// { -// 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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); -// if(!res) throw std::runtime_error("Call to text() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// 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."); - -// detail::_interpreter::get(); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, mappable); - -// 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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); -// if(!res) throw std::runtime_error("Call to colorbar() failed."); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// Py_DECREF(res); -// } - - -// inline long figure(long number = -1) -// { -// detail::_interpreter::get(); - -// 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); - -// // Make sure interpreter is initialised -// 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); -// Py_DECREF(args); -// } - -// 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); - -// Py_DECREF(num); -// Py_DECREF(res); - -// return figureNumber; -// } - -// inline bool fignum_exists(long number) -// { -// detail::_interpreter::get(); - -// 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."); - -// bool ret = PyObject_IsTrue(res); -// Py_DECREF(res); -// Py_DECREF(args); - -// return ret; -// } - -// inline void figure_size(size_t w, size_t h) -// { -// detail::_interpreter::get(); - -// 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)); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "figsize", size); -// PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, -// detail::_interpreter::get().s_python_empty_tuple, kwargs); - -// Py_DECREF(kwargs); - -// if(!res) throw std::runtime_error("Call to figure_size() failed."); -// Py_DECREF(res); -// } - -// inline void legend() -// { -// 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."); - -// Py_DECREF(res); -// } - -// inline void legend(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())); -// } - -// 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(kwargs); -// Py_DECREF(res); -// } - -// template -// inline void set_aspect(Numeric ratio) -// { -// detail::_interpreter::get(); - -// 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 *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); -// } - -// 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* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, list); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); -// if(!res) throw std::runtime_error("Call to ylim() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// template -// 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* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, list); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); -// if(!res) throw std::runtime_error("Call to xlim() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - - -// inline 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."); - -// Py_DECREF(res); - -// PyObject* left = PyTuple_GetItem(res,0); -// PyObject* right = PyTuple_GetItem(res,1); -// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -// } - - -// inline std::array ylim() -// { -// PyObject* args = PyTuple_New(0); -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - -// if(!res) throw std::runtime_error("Call to ylim() failed."); - -// Py_DECREF(res); - -// PyObject* left = PyTuple_GetItem(res,0); -// PyObject* right = PyTuple_GetItem(res,1); -// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -// } - -// template -// inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -// { -// assert(labels.size() == 0 || ticks.size() == labels.size()); - -// detail::_interpreter::get(); - -// // using numpy array -// PyObject* ticksarray = detail::get_array(ticks); - -// 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); -// } - -// // 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(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"); - -// Py_DECREF(res); -// } - -// template -// inline void xticks(const std::vector &ticks, const std::map& keywords) -// { -// xticks(ticks, {}, keywords); -// } - -// template -// inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -// { -// assert(labels.size() == 0 || ticks.size() == labels.size()); - -// detail::_interpreter::get(); - -// // using numpy array -// PyObject* ticksarray = detail::get_array(ticks); - -// 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); -// } - -// // 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(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"); - -// Py_DECREF(res); -// } - -// template -// inline void yticks(const std::vector &ticks, const std::map& keywords) -// { -// yticks(ticks, {}, keywords); -// } - -// template inline void margins(Numeric margin) -// { -// // construct positional args -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); - -// PyObject* res = -// PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); -// if (!res) -// throw std::runtime_error("Call to margins() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// 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_CallObject(detail::_interpreter::get().s_python_function_margins, args); -// if (!res) -// throw std::runtime_error("Call to margins() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - - -// inline void tick_params(const std::map& keywords, const std::string axis = "both") -// { -// detail::_interpreter::get(); - -// // construct positional args -// PyObject* args; -// args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); -// } - - -// 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"); - -// Py_DECREF(res); -// } - -// inline void subplot(long nrows, long ncols, long plot_number) -// { -// detail::_interpreter::get(); - -// // construct positional args -// PyObject* args = PyTuple_New(3); -// PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); -// PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); -// PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); -// if(!res) throw std::runtime_error("Call to subplot() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -// { -// detail::_interpreter::get(); - -// PyObject* shape = PyTuple_New(2); -// PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); -// PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); - -// PyObject* loc = PyTuple_New(2); -// PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); -// PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); - -// 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_subplot2grid, args); -// if(!res) throw std::runtime_error("Call to subplot2grid() failed."); - -// Py_DECREF(shape); -// Py_DECREF(loc); -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void title(const std::string &titlestr, const std::map &keywords = {}) -// { -// detail::_interpreter::get(); - -// 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* 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 suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -// { -// detail::_interpreter::get(); - -// PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pysuptitlestr); - -// 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(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); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); -// if(!res) throw std::runtime_error("Call to title() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -// { -// detail::_interpreter::get(); - -// // 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)); - -// // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); -// } - -// inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -// { -// detail::_interpreter::get(); - -// // 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)); - -// // 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(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)); - -// // 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(); - -// PyObject* pystr = PyString_FromString(str.c_str()); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pystr); - -// 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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); -// if(!res) throw std::runtime_error("Call to xlabel() failed."); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// Py_DECREF(res); -// } - -// inline void ylabel(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); - -// 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(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 set_zlabel(const std::string &str, const std::map& keywords = {}) -// { -// 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) { -// 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* pystr = PyString_FromString(str.c_str()); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pystr); - -// 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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); -// if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); -// Py_INCREF(zlabel); - -// PyObject *res = PyObject_Call(zlabel, args, kwargs); -// if (!res) throw std::runtime_error("Call to set_zlabel() failed."); -// Py_DECREF(zlabel); - -// Py_DECREF(ax); -// Py_DECREF(args); -// Py_DECREF(kwargs); -// if (res) Py_DECREF(res); -// } - -// inline void grid(bool flag) -// { -// detail::_interpreter::get(); - -// PyObject* pyflag = flag ? Py_True : Py_False; -// Py_INCREF(pyflag); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pyflag); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); -// if(!res) throw std::runtime_error("Call to grid() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void show(const bool block = true) -// { -// 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."); - -// Py_DECREF(res); -// } - -// inline void close() -// { -// detail::_interpreter::get(); - -// 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); - -// 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); - -// if (!res) throw std::runtime_error("Call to draw() failed."); - -// Py_DECREF(res); -// } - -// template -// inline void pause(Numeric interval) -// { -// detail::_interpreter::get(); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); -// if(!res) throw std::runtime_error("Call to pause() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void save(const std::string& filename, const int dpi=0) -// { -// detail::_interpreter::get(); - -// PyObject* pyfilename = PyString_FromString(filename.c_str()); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pyfilename); - -// PyObject* kwargs = PyDict_New(); - -// if(dpi > 0) -// { -// PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); -// } - -// 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(args); -// Py_DECREF(kwargs); -// Py_DECREF(res); -// } - -// 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 * 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); - -// if (!res) throw std::runtime_error("Call to clf() failed."); - -// Py_DECREF(res); -// } - -// inline void cla() { -// detail::_interpreter::get(); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, -// detail::_interpreter::get().s_python_empty_tuple); - -// if (!res) -// throw std::runtime_error("Call to cla() failed."); - -// Py_DECREF(res); -// } - -// inline void ion() { -// detail::_interpreter::get(); - -// PyObject *res = PyObject_CallObject( -// detail::_interpreter::get().s_python_function_ion, -// detail::_interpreter::get().s_python_empty_tuple); - -// if (!res) throw std::runtime_error("Call to ion() failed."); - -// Py_DECREF(res); -// } - -// inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -// { -// detail::_interpreter::get(); - -// PyObject *args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); - -// // 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_ginput, args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(args); -// if (!res) throw std::runtime_error("Call to ginput() 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); - -// return out; -// } - -// // Actually, is there any reason not to call this automatically for every plot? -// inline void tight_layout() { -// detail::_interpreter::get(); - -// PyObject *res = PyObject_CallObject( -// detail::_interpreter::get().s_python_function_tight_layout, -// detail::_interpreter::get().s_python_empty_tuple); - -// if (!res) throw std::runtime_error("Call to tight_layout() failed."); - -// Py_DECREF(res); -// } - -// // Support for variadic plot() and initializer lists: - -// namespace detail { - -// template -// using is_function = typename std::is_function>>::type; - -// template -// struct is_callable_impl; - -// template -// struct is_callable_impl -// { -// typedef is_function type; -// }; // a non-object is callable iff it is a function - -// 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; -// }; - -// template -// struct plot_impl { }; - -// 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::distance; -// using std::begin; -// using std::end; - -// auto xs = distance(begin(x), end(x)); -// auto ys = distance(begin(y), end(y)); -// assert(xs == ys && "x and y data must have the same number of elements!"); - -// PyObject* xlist = PyList_New(xs); -// PyObject* ylist = PyList_New(ys); -// PyObject* pystring = PyString_FromString(format.c_str()); - -// auto itx = begin(x), ity = begin(y); -// for(size_t i = 0; i < xs; ++i) { -// PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); -// PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); -// } - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xlist); -// PyTuple_SetItem(plot_args, 1, ylist); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(res); - -// return res; -// } -// }; - -// template<> -// struct plot_impl -// { -// 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...); -// } - -// /* -// * 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); -// } - -// inline bool plot(const std::vector& y, const std::string& format = "") { -// return plot(y,format); -// } - -// inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { -// return plot(x,y,keywords); -// } - -// /* -// * 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(); - -// assert(x.size() == y.size()); - -// PyObject* kwargs = PyDict_New(); -// if(name != "") -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); - -// if(res) -// { -// line= PyList_GetItem(res, 0); - -// if(line) -// set_data_fct = PyObject_GetAttrString(line,"set_data"); -// else -// Py_DECREF(line); -// Py_DECREF(res); -// } -// } - -// // 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) -// { -// 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; -// } - -// // clears the plot but keep it available -// bool clear() { -// return update(std::vector(), std::vector()); -// } - -// // definitely remove this line -// void remove() { -// 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(); -// } - -// ~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; -// }; - -// } // end namespace matplotlibcpp -#pragma once - -// Python headers must be included before any system headers, since -// they define _POSIX_C_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include // requires c++11 support -#include -#include // std::stod - -#ifndef WITHOUT_NUMPY -# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -# include - -# 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 -#endif // WITHOUT_NUMPY - -#if PY_MAJOR_VERSION >= 3 -# define PyString_FromString PyUnicode_FromString -# define PyInt_FromLong PyLong_FromLong -# define PyString_FromString PyUnicode_FromString -#endif - - -namespace matplotlibcpp { -namespace detail { - -static std::string s_backend; - -struct _interpreter { - PyObject* pymod; - 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 - - void *import_numpy() { - import_array(); // initialize C-API - return NULL; - } - -# else - - void import_numpy() { - import_array(); // initialize C-API - } - -# endif -#endif - - _interpreter() { - - // optional but recommended -#if PY_MAJOR_VERSION >= 3 - wchar_t name[] = L"plotting"; -#else - char name[] = "plotting"; -#endif - Py_SetProgramName(name); - Py_Initialize(); - - 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)); -#else - PySys_SetArgv(argc, (char **)(argv)); -#endif - -#ifndef WITHOUT_NUMPY - 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()); - } - - - - pymod = PyImport_Import(pyplotname); - Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } - - PyObject * mpl_toolkitsmod; - PyObject * axis3dmod; - 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!"); } - } - - - - - - - - - - - - - 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"); -#endif - 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; -} - -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()); - - PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); - PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "xy", xy); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); - - return res; -} - -PyObject * chart(int place) -{ - PyObject * drawObject = PyObject_GetAttrString(detail::_interpreter::get().pymod, "subplot"); - PyObject * args = PyTuple_New(1); - PyObject * kwargs = PyDict_New(); - PyTuple_SetItem(args, 0, PyLong_FromLong(place)); - PyDict_SetItemString(kwargs, "projection", PyUnicode_FromString("3d")); - PyObject * thePlot = PyObject_Call(drawObject, args, kwargs); - return thePlot; -} - -inline void Clear3DChart(PyObject * ax) -{ - PyObject * eraser = PyObject_GetAttrString(ax, "cla"); - PyObject * args = PyTuple_New(0); - PyObject_CallObject(eraser, args); -} - -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; -} - - -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())}; - - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - - 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]; - } - - 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; -} - -#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(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -// TODO - it should be possible to make this work by implementing -// a non-numpy alternative for `detail::get_2darray()`. -#ifndef WITHOUT_NUMPY -template -void surface3D(PyObject * ax, - const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - std::string color, - double linewidth) -{ - PyObject * X = detail::get_2darray(x); - PyObject * Y = detail::get_2darray(y); - PyObject * Z = detail::get_2darray(z); - - PyObject * args = PyTuple_New(3); - PyObject * kwargs = PyDict_New(); - PyTuple_SetItem(args, 0, X); - PyTuple_SetItem(args, 1, Y); - PyTuple_SetItem(args, 2, Z); - PyDict_SetItemString(kwargs, "color", PyUnicode_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "linewidth", PyLong_FromLong(linewidth)); - - - PyObject * thePlot = PyObject_GetAttrString(ax, "plot_surface"); - PyObject_Call(thePlot, args, kwargs); -} - -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 - -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()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); - - return res; -} - -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (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(detail::_interpreter::get().s_python_function_fill, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if (res) Py_DECREF(res); - - return res; -} - -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); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); - - return res; -} - -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(); - - PyObject* yarray = detail::get_array(y); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); - PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); - PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); - - 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; -} - -#ifndef WITHOUT_NUMPY -namespace detail { - -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); -} - -} // 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); -} - -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); -} - -#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 - -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(); - - assert(x.size() == y.size()); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - 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); - - 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 = {}) - { - 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); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - PyDict_SetItemString(kwargs, "c", colors_array); - - 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); - - 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(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(); - - // 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)); - } - - // take care of the remaining keywords - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); - - return res; -} - -template -bool boxplot(const std::vector& data, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* vector = detail::get_array(data); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, vector); - - PyObject* kwargs = PyDict_New(); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); - - 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())); - } - - 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 = {}) -{ - 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; -} - -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* 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); - - 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()); - - 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); - - return res; -} - -template -bool semilogx(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_semilogx, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; -} - -template -bool semilogy(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_semilogy, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; -} - -template -bool loglog(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_loglog, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(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()); - - 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); - - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - - if (res) - Py_DECREF(res); - else - throw std::runtime_error("Call to errorbar() failed."); - - return res; -} - -template -bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(2); - - PyTuple_SetItem(plot_args, 0, yarray); - PyTuple_SetItem(plot_args, 1, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -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); -} - -template -void text(Numeric x, Numeric y, const std::string& s = "") -{ - 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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); - if(!res) throw std::runtime_error("Call to text() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -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."); - - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, mappable); - - 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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); - if(!res) throw std::runtime_error("Call to colorbar() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - - -inline long figure(long number = -1) -{ - detail::_interpreter::get(); - - 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); - - // Make sure interpreter is initialised - 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); - Py_DECREF(args); - } - - 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); - - Py_DECREF(num); - Py_DECREF(res); - - return figureNumber; -} - -inline bool fignum_exists(long number) -{ - detail::_interpreter::get(); - - 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."); - - bool ret = PyObject_IsTrue(res); - Py_DECREF(res); - Py_DECREF(args); - - return ret; -} - -inline void figure_size(size_t w, size_t h) -{ - detail::_interpreter::get(); - - 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)); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "figsize", size); - PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); - - Py_DECREF(kwargs); - - if(!res) throw std::runtime_error("Call to figure_size() failed."); - Py_DECREF(res); -} - -inline void legend() -{ - 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."); - - Py_DECREF(res); -} - -inline void legend(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())); - } - - 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(kwargs); - Py_DECREF(res); -} - -template -inline void set_aspect(Numeric ratio) -{ - detail::_interpreter::get(); - - 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 *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); -} - -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* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - if(!res) throw std::runtime_error("Call to ylim() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -template -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* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - if(!res) throw std::runtime_error("Call to xlim() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - - -inline 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."); - - Py_DECREF(res); - - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -} - - -inline std::array ylim() -{ - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - - if(!res) throw std::runtime_error("Call to ylim() failed."); - - Py_DECREF(res); - - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -} - -template -inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); - - detail::_interpreter::get(); - - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); - - 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); - } - - // 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(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"); - - Py_DECREF(res); -} - -template -inline void xticks(const std::vector &ticks, const std::map& keywords) -{ - xticks(ticks, {}, keywords); -} - -template -inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); - - detail::_interpreter::get(); - - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); - - 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); - } - - // 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(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"); - - Py_DECREF(res); -} - -template -inline void yticks(const std::vector &ticks, const std::map& keywords) -{ - yticks(ticks, {}, keywords); -} - -template inline void margins(Numeric margin) -{ - // construct positional args - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); - - PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -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_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - - -inline void tick_params(const std::map& keywords, const std::string axis = "both") -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args; - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); - } - - - 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"); - - Py_DECREF(res); -} - -inline void subplot(long nrows, long ncols, long plot_number) -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); - if(!res) throw std::runtime_error("Call to subplot() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -{ - detail::_interpreter::get(); - - PyObject* shape = PyTuple_New(2); - PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); - PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); - - PyObject* loc = PyTuple_New(2); - PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); - PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); - - 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_subplot2grid, args); - if(!res) throw std::runtime_error("Call to subplot2grid() failed."); - - Py_DECREF(shape); - Py_DECREF(loc); - Py_DECREF(args); - Py_DECREF(res); -} - -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - 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* 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 suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pysuptitlestr); - - 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(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); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); - - // 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)); - - // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); -} - -inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); - - // 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)); - - // 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(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)); - - // 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(); - - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); - - 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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void ylabel(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); - - 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(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 set_zlabel(const std::string &str, const std::map& keywords = {}) -{ - 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) { - 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* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); - - 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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); - if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); - Py_INCREF(zlabel); - - PyObject *res = PyObject_Call(zlabel, args, kwargs); - if (!res) throw std::runtime_error("Call to set_zlabel() failed."); - Py_DECREF(zlabel); - - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -inline void grid(bool flag) -{ - detail::_interpreter::get(); - - PyObject* pyflag = flag ? Py_True : Py_False; - Py_INCREF(pyflag); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyflag); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void show(const bool block = true) -{ - 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."); - - Py_DECREF(res); -} - -inline void close() -{ - detail::_interpreter::get(); - - 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); - - 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); - - if (!res) throw std::runtime_error("Call to draw() failed."); - - Py_DECREF(res); -} - -template -inline void pause(Numeric interval) -{ - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); - if(!res) throw std::runtime_error("Call to pause() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void save(const std::string& filename, const int dpi=0) -{ - detail::_interpreter::get(); - - PyObject* pyfilename = PyString_FromString(filename.c_str()); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyfilename); - - PyObject* kwargs = PyDict_New(); - - if(dpi > 0) - { - PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); - } - - 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(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -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 * 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); - - if (!res) throw std::runtime_error("Call to clf() failed."); - - Py_DECREF(res); -} - -inline void cla() { - detail::_interpreter::get(); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) - throw std::runtime_error("Call to cla() failed."); - - Py_DECREF(res); -} - -inline void ion() { - detail::_interpreter::get(); - - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to ion() failed."); - - Py_DECREF(res); -} - -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ - detail::_interpreter::get(); - - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); - - // 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_ginput, args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(args); - if (!res) throw std::runtime_error("Call to ginput() 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); - - return out; -} - -// Actually, is there any reason not to call this automatically for every plot? -inline void tight_layout() { - detail::_interpreter::get(); - - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_tight_layout, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to tight_layout() failed."); - - Py_DECREF(res); -} - -// Support for variadic plot() and initializer lists: - -namespace detail { - -template -using is_function = typename std::is_function>>::type; - -template -struct is_callable_impl; - -template -struct is_callable_impl -{ - typedef is_function type; -}; // a non-object is callable iff it is a function - -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; -}; - -template -struct plot_impl { }; - -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::distance; - using std::begin; - using std::end; - - auto xs = distance(begin(x), end(x)); - auto ys = distance(begin(y), end(y)); - assert(xs == ys && "x and y data must have the same number of elements!"); - - PyObject* xlist = PyList_New(xs); - PyObject* ylist = PyList_New(ys); - PyObject* pystring = PyString_FromString(format.c_str()); - - auto itx = begin(x), ity = begin(y); - for(size_t i = 0; i < xs; ++i) { - PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); - PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); - } - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xlist); - PyTuple_SetItem(plot_args, 1, ylist); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; - } -}; - -template<> -struct plot_impl -{ - 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...); -} - -/* - * 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); -} - -inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(y,format); -} - -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); -} - -/* - * 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(); - - assert(x.size() == y.size()); - - PyObject* kwargs = PyDict_New(); - if(name != "") - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - - if(res) - { - line= PyList_GetItem(res, 0); - - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); - else - Py_DECREF(line); - Py_DECREF(res); - } - } - - // 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) - { - 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; - } - - // clears the plot but keep it available - bool clear() { - return update(std::vector(), std::vector()); - } - - // definitely remove this line - void remove() { - 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(); - } - - ~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; -}; - -} // end namespace matplotlibcpp \ No newline at end of file diff --git a/install/lib/cmake/matplotlibcpp_lib-config.cmake b/install/lib/cmake/matplotlibcpp_lib-config.cmake deleted file mode 100644 index 3a32769..0000000 --- a/install/lib/cmake/matplotlibcpp_lib-config.cmake +++ /dev/null @@ -1,7 +0,0 @@ -include(CMakeFindDependencyMacro) - -find_dependency(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) -find_dependency(PythonLibs 3.0 REQUIRED) - -get_filename_component(SELF_DIR ${CMAKE_CURRENT_LIST_DIR} PATH) -include(${SELF_DIR}/cmake/matplotlibcpp_lib.cmake) \ No newline at end of file diff --git a/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake b/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake deleted file mode 100644 index 4901355..0000000 --- a/install/lib/cmake/matplotlibcpp_lib-noconfig.cmake +++ /dev/null @@ -1,19 +0,0 @@ -#---------------------------------------------------------------- -# Generated CMake target import file. -#---------------------------------------------------------------- - -# Commands may need to know the format version. -set(CMAKE_IMPORT_FILE_VERSION 1) - -# Import target "matplotlibcpp_lib" for configuration "" -set_property(TARGET matplotlibcpp_lib APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) -set_target_properties(matplotlibcpp_lib PROPERTIES - IMPORTED_LOCATION_NOCONFIG "/home/jonarriza96/papor/external/matplotlibcpp/install/lib/libmatplotlibcpp_lib.so" - IMPORTED_SONAME_NOCONFIG "libmatplotlibcpp_lib.so" - ) - -list(APPEND _cmake_import_check_targets matplotlibcpp_lib ) -list(APPEND _cmake_import_check_files_for_matplotlibcpp_lib "/home/jonarriza96/papor/external/matplotlibcpp/install/lib/libmatplotlibcpp_lib.so" ) - -# Commands beyond this point should not need to know the version. -set(CMAKE_IMPORT_FILE_VERSION) diff --git a/install/lib/cmake/matplotlibcpp_lib.cmake b/install/lib/cmake/matplotlibcpp_lib.cmake deleted file mode 100644 index 221ed17..0000000 --- a/install/lib/cmake/matplotlibcpp_lib.cmake +++ /dev/null @@ -1,101 +0,0 @@ -# Generated by CMake - -if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) - message(FATAL_ERROR "CMake >= 2.8.0 required") -endif() -if(CMAKE_VERSION VERSION_LESS "2.8.3") - message(FATAL_ERROR "CMake >= 2.8.3 required") -endif() -cmake_policy(PUSH) -cmake_policy(VERSION 2.8.3...3.26) -#---------------------------------------------------------------- -# Generated CMake target import file. -#---------------------------------------------------------------- - -# Commands may need to know the format version. -set(CMAKE_IMPORT_FILE_VERSION 1) - -# Protect against multiple inclusion, which would fail when already imported targets are added once more. -set(_cmake_targets_defined "") -set(_cmake_targets_not_defined "") -set(_cmake_expected_targets "") -foreach(_cmake_expected_target IN ITEMS matplotlibcpp_lib) - list(APPEND _cmake_expected_targets "${_cmake_expected_target}") - if(TARGET "${_cmake_expected_target}") - list(APPEND _cmake_targets_defined "${_cmake_expected_target}") - else() - list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") - endif() -endforeach() -unset(_cmake_expected_target) -if(_cmake_targets_defined STREQUAL _cmake_expected_targets) - unset(_cmake_targets_defined) - unset(_cmake_targets_not_defined) - unset(_cmake_expected_targets) - unset(CMAKE_IMPORT_FILE_VERSION) - cmake_policy(POP) - return() -endif() -if(NOT _cmake_targets_defined STREQUAL "") - string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") - string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") - message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") -endif() -unset(_cmake_targets_defined) -unset(_cmake_targets_not_defined) -unset(_cmake_expected_targets) - - -# The installation prefix configured by this project. -set(_IMPORT_PREFIX "/home/jonarriza96/papor/external/matplotlibcpp/install") - -# Create imported target matplotlibcpp_lib -add_library(matplotlibcpp_lib SHARED IMPORTED) - -set_target_properties(matplotlibcpp_lib PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "/home/jonarriza96/papor/external/matplotlibcpp/install/include;/home/jonarriza96/papor/external/matplotlibcpp/install/src" - INTERFACE_LINK_LIBRARIES "/usr/lib/x86_64-linux-gnu/libpython3.8.so;Python3::NumPy" -) - -if(CMAKE_VERSION VERSION_LESS 2.8.12) - message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") -endif() - -# Load information for each installed configuration. -file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/matplotlibcpp_lib-*.cmake") -foreach(_cmake_config_file IN LISTS _cmake_config_files) - include("${_cmake_config_file}") -endforeach() -unset(_cmake_config_file) -unset(_cmake_config_files) - -# Cleanup temporary variables. -set(_IMPORT_PREFIX) - -# Loop over all imported files and verify that they actually exist -foreach(_cmake_target IN LISTS _cmake_import_check_targets) - foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") - if(NOT EXISTS "${_cmake_file}") - message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file - \"${_cmake_file}\" -but this file does not exist. Possible reasons include: -* The file was deleted, renamed, or moved to another location. -* An install or uninstall procedure did not complete successfully. -* The installation package was faulty and contained - \"${CMAKE_CURRENT_LIST_FILE}\" -but not all the files it references. -") - endif() - endforeach() - unset(_cmake_file) - unset("_cmake_import_check_files_for_${_cmake_target}") -endforeach() -unset(_cmake_target) -unset(_cmake_import_check_targets) - -# This file does not depend on other imported targets which have -# been exported from the same project but in a separate export set. - -# Commands beyond this point should not need to know the version. -set(CMAKE_IMPORT_FILE_VERSION) -cmake_policy(POP) diff --git a/install/src/matplotlibcpp.cpp b/install/src/matplotlibcpp.cpp deleted file mode 100644 index e7914e1..0000000 --- a/install/src/matplotlibcpp.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "matplotlibcpp.h" \ No newline at end of file From dfb9e4aefa3a1a9db2188e5cbfac7f8531c3d227 Mon Sep 17 00:00:00 2001 From: Jon Arrizabalaga Date: Sat, 30 Mar 2024 12:20:59 -0400 Subject: [PATCH 7/7] added axis_equal, clang formatting --- include/matplotlibcpp.h | 7188 ++++++++++++--------------------------- 1 file changed, 2218 insertions(+), 4970 deletions(-) diff --git a/include/matplotlibcpp.h b/include/matplotlibcpp.h index 0adc313..81aead5 100644 --- a/include/matplotlibcpp.h +++ b/include/matplotlibcpp.h @@ -1,3334 +1,317 @@ -// #pragma once - -// // Python headers must be included before any system headers, since -// // they define _POSIX_C_SOURCE -// #include - -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include // requires c++11 support -// #include -// #include // std::stod - -// #ifndef WITHOUT_NUMPY -// # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -// # include - -// # 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 -// #endif // WITHOUT_NUMPY - -// #if PY_MAJOR_VERSION >= 3 -// # define PyString_FromString PyUnicode_FromString -// # define PyInt_FromLong PyLong_FromLong -// # define PyString_FromString PyUnicode_FromString -// #endif - - -// namespace matplotlibcpp { -// namespace detail { - -// static std::string s_backend; - -// struct _interpreter { -// PyObject *pymod; -// 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 - -// void *import_numpy() { -// import_array(); // initialize C-API -// return NULL; -// } - -// # else - -// void import_numpy() { -// import_array(); // initialize C-API -// } - -// # endif -// #endif - -// _interpreter() { - -// // optional but recommended -// #if PY_MAJOR_VERSION >= 3 -// wchar_t name[] = L"plotting"; -// #else -// char name[] = "plotting"; -// #endif -// Py_SetProgramName(name); -// Py_Initialize(); - -// 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)); -// #else -// PySys_SetArgv(argc, (char **)(argv)); -// #endif - -// #ifndef WITHOUT_NUMPY -// 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 * mpl_toolkitsmod; -// PyObject * axis3dmod; -// 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!"); } -// } - - -// 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"); -// #endif -// 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; -// } - -// 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()); - -// PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); -// PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "xy", xy); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, str); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); - -// return res; -// } - -// PyObject * chart(int place) -// { -// PyObject * drawObject=PyObject_GetAttrString(detail::_interpreter::get().pymod,"subplot"); -// PyObject * args = PyTuple_New(1); -// PyObject * kwargs =PyDict_New(); -// PyTuple_SetItem(args,0,PyLong_FromLong(place)); -// PyDict_SetItemString(kwargs,"projection",PyUnicode_FromString("3d")); -// PyObject * thePlot=PyObject_Call(drawObject,args,kwargs); -// return thePlot; -// } - -// 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; -// } - - -// 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())}; - -// PyArrayObject *varray = -// (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - -// 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]; -// } - -// 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; -// } - -// #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(); - -// // using numpy arrays -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// // construct positional args -// PyObject* args = PyTuple_New(2); -// PyTuple_SetItem(args, 0, xarray); -// PyTuple_SetItem(args, 1, yarray); - -// // construct keyword args -// PyObject* kwargs = PyDict_New(); -// for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) -// { -// PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); -// } - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// if(res) Py_DECREF(res); - -// return res; -// } - -// // 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 - -// 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()); - -// detail::_interpreter::get(); - -// // using numpy arrays -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// // construct positional args -// PyObject* args = PyTuple_New(2); -// PyTuple_SetItem(args, 0, xarray); -// PyTuple_SetItem(args, 1, yarray); - -// // construct keyword args -// PyObject* kwargs = PyDict_New(); -// for (std::map::const_iterator it = -// keywords.begin(); it != keywords.end(); ++it) { -// PyDict_SetItemString(kwargs, it->first.c_str(), -// PyString_FromString(it->second.c_str())); -// } - -// PyObject* res = PyObject_Call( -// detail::_interpreter::get().s_python_function_stem, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// if (res) -// Py_DECREF(res); - -// return res; -// } - -// template< typename Numeric > -// bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -// { -// assert(x.size() == y.size()); - -// detail::_interpreter::get(); - -// // using numpy arrays -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// // construct positional args -// PyObject* args = PyTuple_New(2); -// PyTuple_SetItem(args, 0, xarray); -// PyTuple_SetItem(args, 1, yarray); - -// // construct keyword args -// PyObject* kwargs = PyDict_New(); -// for (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(detail::_interpreter::get().s_python_function_fill, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if (res) Py_DECREF(res); - -// return res; -// } - -// 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); - -// Py_DECREF(plot_args); -// Py_DECREF(kwargs); -// if (res) -// Py_DECREF(res); - -// return res; -// } - -// 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(); - -// PyObject* yarray = detail::get_array(y); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); -// PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); -// PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); -// PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); - -// 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; -// } - -// #ifndef WITHOUT_NUMPY -// namespace detail { - -// 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); -// } - -// } // 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); -// } - -// 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); -// } - -// #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 - -// 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(); - -// assert(x.size() == y.size()); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// 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); - -// 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 = {}) -// { -// 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); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); -// PyDict_SetItemString(kwargs, "c", colors_array); - -// 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); - -// 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(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(); - -// // 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)); -// } - -// // take care of the remaining keywords -// for (const auto& it : keywords) -// { -// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); -// } - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); - -// return res; -// } - -// template -// bool boxplot(const std::vector& data, -// const std::map & keywords = {}) -// { -// detail::_interpreter::get(); - -// PyObject* vector = detail::get_array(data); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, vector); - -// PyObject* kwargs = PyDict_New(); -// for (const auto& it : keywords) -// { -// PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); -// } - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); - -// 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())); -// } - -// 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 = {}) -// { -// 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; -// } - -// 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* 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); - -// 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()); - -// 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); - -// return res; -// } - -// template -// bool semilogx(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_semilogx, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(res); - -// return res; -// } - -// template -// bool semilogy(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_semilogy, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(res); - -// return res; -// } - -// template -// bool loglog(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_loglog, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(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()); - -// 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); - -// PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); - -// if (res) -// Py_DECREF(res); -// else -// throw std::runtime_error("Call to errorbar() failed."); - -// return res; -// } - -// template -// bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(2); - -// PyTuple_SetItem(plot_args, 0, yarray); -// PyTuple_SetItem(plot_args, 1, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -// { -// detail::_interpreter::get(); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); -// if (res) Py_DECREF(res); - -// return res; -// } - -// template -// 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); -// } - -// template -// void text(Numeric x, Numeric y, const std::string& s = "") -// { -// 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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); -// if(!res) throw std::runtime_error("Call to text() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// 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."); - -// detail::_interpreter::get(); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, mappable); - -// 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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); -// if(!res) throw std::runtime_error("Call to colorbar() failed."); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// Py_DECREF(res); -// } - - -// inline long figure(long number = -1) -// { -// detail::_interpreter::get(); - -// 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); - -// // Make sure interpreter is initialised -// 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); -// Py_DECREF(args); -// } - -// 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); - -// Py_DECREF(num); -// Py_DECREF(res); - -// return figureNumber; -// } - -// inline bool fignum_exists(long number) -// { -// detail::_interpreter::get(); - -// 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."); - -// bool ret = PyObject_IsTrue(res); -// Py_DECREF(res); -// Py_DECREF(args); - -// return ret; -// } - -// inline void figure_size(size_t w, size_t h) -// { -// detail::_interpreter::get(); - -// 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)); - -// PyObject* kwargs = PyDict_New(); -// PyDict_SetItemString(kwargs, "figsize", size); -// PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, -// detail::_interpreter::get().s_python_empty_tuple, kwargs); - -// Py_DECREF(kwargs); - -// if(!res) throw std::runtime_error("Call to figure_size() failed."); -// Py_DECREF(res); -// } - -// inline void legend() -// { -// 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."); - -// Py_DECREF(res); -// } - -// inline void legend(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())); -// } - -// 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(kwargs); -// Py_DECREF(res); -// } - -// template -// inline void set_aspect(Numeric ratio) -// { -// detail::_interpreter::get(); - -// 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 *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); -// } - -// 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* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, list); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); -// if(!res) throw std::runtime_error("Call to ylim() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// template -// 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* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, list); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); -// if(!res) throw std::runtime_error("Call to xlim() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - - -// inline 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."); - -// Py_DECREF(res); - -// PyObject* left = PyTuple_GetItem(res,0); -// PyObject* right = PyTuple_GetItem(res,1); -// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -// } - - -// inline std::array ylim() -// { -// PyObject* args = PyTuple_New(0); -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - -// if(!res) throw std::runtime_error("Call to ylim() failed."); - -// Py_DECREF(res); - -// PyObject* left = PyTuple_GetItem(res,0); -// PyObject* right = PyTuple_GetItem(res,1); -// return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -// } - -// template -// inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -// { -// assert(labels.size() == 0 || ticks.size() == labels.size()); - -// detail::_interpreter::get(); - -// // using numpy array -// PyObject* ticksarray = detail::get_array(ticks); - -// 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); -// } - -// // 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(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"); - -// Py_DECREF(res); -// } - -// template -// inline void xticks(const std::vector &ticks, const std::map& keywords) -// { -// xticks(ticks, {}, keywords); -// } - -// template -// inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -// { -// assert(labels.size() == 0 || ticks.size() == labels.size()); - -// detail::_interpreter::get(); - -// // using numpy array -// PyObject* ticksarray = detail::get_array(ticks); - -// 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); -// } - -// // 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(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"); - -// Py_DECREF(res); -// } - -// template -// inline void yticks(const std::vector &ticks, const std::map& keywords) -// { -// yticks(ticks, {}, keywords); -// } - -// template inline void margins(Numeric margin) -// { -// // construct positional args -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); - -// PyObject* res = -// PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); -// if (!res) -// throw std::runtime_error("Call to margins() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// 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_CallObject(detail::_interpreter::get().s_python_function_margins, args); -// if (!res) -// throw std::runtime_error("Call to margins() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - - -// inline void tick_params(const std::map& keywords, const std::string axis = "both") -// { -// detail::_interpreter::get(); - -// // construct positional args -// PyObject* args; -// args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); -// } - - -// 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"); - -// Py_DECREF(res); -// } - -// inline void subplot(long nrows, long ncols, long plot_number) -// { -// detail::_interpreter::get(); - -// // construct positional args -// PyObject* args = PyTuple_New(3); -// PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); -// PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); -// PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); -// if(!res) throw std::runtime_error("Call to subplot() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -// { -// detail::_interpreter::get(); - -// PyObject* shape = PyTuple_New(2); -// PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); -// PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); - -// PyObject* loc = PyTuple_New(2); -// PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); -// PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); - -// 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_subplot2grid, args); -// if(!res) throw std::runtime_error("Call to subplot2grid() failed."); - -// Py_DECREF(shape); -// Py_DECREF(loc); -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void title(const std::string &titlestr, const std::map &keywords = {}) -// { -// detail::_interpreter::get(); - -// 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* 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 suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -// { -// detail::_interpreter::get(); - -// PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pysuptitlestr); - -// 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(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); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); -// if(!res) throw std::runtime_error("Call to title() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -// { -// detail::_interpreter::get(); - -// // 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)); - -// // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); - -// Py_DECREF(args); -// Py_DECREF(kwargs); - -// if(res) Py_DECREF(res); -// } - -// inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -// { -// detail::_interpreter::get(); - -// // 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)); - -// // 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(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)); - -// // 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(); - -// PyObject* pystr = PyString_FromString(str.c_str()); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pystr); - -// 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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); -// if(!res) throw std::runtime_error("Call to xlabel() failed."); - -// Py_DECREF(args); -// Py_DECREF(kwargs); -// Py_DECREF(res); -// } - -// inline void ylabel(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); - -// 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(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 set_zlabel(const std::string &str, const std::map& keywords = {}) -// { -// 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) { -// 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* pystr = PyString_FromString(str.c_str()); -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pystr); - -// 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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); -// if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); -// Py_INCREF(zlabel); - -// PyObject *res = PyObject_Call(zlabel, args, kwargs); -// if (!res) throw std::runtime_error("Call to set_zlabel() failed."); -// Py_DECREF(zlabel); - -// Py_DECREF(ax); -// Py_DECREF(args); -// Py_DECREF(kwargs); -// if (res) Py_DECREF(res); -// } - -// inline void grid(bool flag) -// { -// detail::_interpreter::get(); - -// PyObject* pyflag = flag ? Py_True : Py_False; -// Py_INCREF(pyflag); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pyflag); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); -// if(!res) throw std::runtime_error("Call to grid() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void show(const bool block = true) -// { -// 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."); - -// Py_DECREF(res); -// } - -// inline void close() -// { -// detail::_interpreter::get(); - -// 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); - -// 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); - -// if (!res) throw std::runtime_error("Call to draw() failed."); - -// Py_DECREF(res); -// } - -// template -// inline void pause(Numeric interval) -// { -// detail::_interpreter::get(); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); -// if(!res) throw std::runtime_error("Call to pause() failed."); - -// Py_DECREF(args); -// Py_DECREF(res); -// } - -// inline void save(const std::string& filename, const int dpi=0) -// { -// detail::_interpreter::get(); - -// PyObject* pyfilename = PyString_FromString(filename.c_str()); - -// PyObject* args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, pyfilename); - -// PyObject* kwargs = PyDict_New(); - -// if(dpi > 0) -// { -// PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); -// } - -// 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(args); -// Py_DECREF(kwargs); -// Py_DECREF(res); -// } - -// 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 * 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); - -// if (!res) throw std::runtime_error("Call to clf() failed."); - -// Py_DECREF(res); -// } - -// inline void cla() { -// detail::_interpreter::get(); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, -// detail::_interpreter::get().s_python_empty_tuple); - -// if (!res) -// throw std::runtime_error("Call to cla() failed."); - -// Py_DECREF(res); -// } - -// inline void ion() { -// detail::_interpreter::get(); - -// PyObject *res = PyObject_CallObject( -// detail::_interpreter::get().s_python_function_ion, -// detail::_interpreter::get().s_python_empty_tuple); - -// if (!res) throw std::runtime_error("Call to ion() failed."); - -// Py_DECREF(res); -// } - -// inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -// { -// detail::_interpreter::get(); - -// PyObject *args = PyTuple_New(1); -// PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); - -// // 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_ginput, args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(args); -// if (!res) throw std::runtime_error("Call to ginput() 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); - -// return out; -// } - -// // Actually, is there any reason not to call this automatically for every plot? -// inline void tight_layout() { -// detail::_interpreter::get(); - -// PyObject *res = PyObject_CallObject( -// detail::_interpreter::get().s_python_function_tight_layout, -// detail::_interpreter::get().s_python_empty_tuple); - -// if (!res) throw std::runtime_error("Call to tight_layout() failed."); - -// Py_DECREF(res); -// } - -// // Support for variadic plot() and initializer lists: - -// namespace detail { - -// template -// using is_function = typename std::is_function>>::type; - -// template -// struct is_callable_impl; - -// template -// struct is_callable_impl -// { -// typedef is_function type; -// }; // a non-object is callable iff it is a function - -// 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; -// }; - -// template -// struct plot_impl { }; - -// 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::distance; -// using std::begin; -// using std::end; - -// auto xs = distance(begin(x), end(x)); -// auto ys = distance(begin(y), end(y)); -// assert(xs == ys && "x and y data must have the same number of elements!"); - -// PyObject* xlist = PyList_New(xs); -// PyObject* ylist = PyList_New(ys); -// PyObject* pystring = PyString_FromString(format.c_str()); - -// auto itx = begin(x), ity = begin(y); -// for(size_t i = 0; i < xs; ++i) { -// PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); -// PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); -// } - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xlist); -// PyTuple_SetItem(plot_args, 1, ylist); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); - -// Py_DECREF(plot_args); -// if(res) Py_DECREF(res); - -// return res; -// } -// }; - -// template<> -// struct plot_impl -// { -// 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...); -// } - -// /* -// * 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); -// } - -// inline bool plot(const std::vector& y, const std::string& format = "") { -// return plot(y,format); -// } - -// inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { -// return plot(x,y,keywords); -// } - -// /* -// * 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(); - -// assert(x.size() == y.size()); - -// PyObject* kwargs = PyDict_New(); -// if(name != "") -// PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - -// PyObject* xarray = detail::get_array(x); -// PyObject* yarray = detail::get_array(y); - -// PyObject* pystring = PyString_FromString(format.c_str()); - -// PyObject* plot_args = PyTuple_New(3); -// PyTuple_SetItem(plot_args, 0, xarray); -// PyTuple_SetItem(plot_args, 1, yarray); -// PyTuple_SetItem(plot_args, 2, pystring); - -// PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - -// Py_DECREF(kwargs); -// Py_DECREF(plot_args); - -// if(res) -// { -// line= PyList_GetItem(res, 0); - -// if(line) -// set_data_fct = PyObject_GetAttrString(line,"set_data"); -// else -// Py_DECREF(line); -// Py_DECREF(res); -// } -// } - -// // 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) -// { -// 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; -// } - -// // clears the plot but keep it available -// bool clear() { -// return update(std::vector(), std::vector()); -// } - -// // definitely remove this line -// void remove() { -// 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(); -// } - -// ~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; -// }; - -// } // end namespace matplotlibcpp #pragma once // Python headers must be included before any system headers, since // they define _POSIX_C_SOURCE #include -#include -#include -#include -#include #include -#include -#include +#include #include // requires c++11 support #include +#include +#include +#include +#include #include // std::stod +#include #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 { static std::string s_backend; struct _interpreter { - PyObject* pymod; - 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 *pymod; + 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()); + 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 (!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.")); + if (!PyFunction_Check(fn)) + throw std::runtime_error( + fname + std::string(" is unexpectedly not a PyFunction.")); - return fn; - } + 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()); - } - - - - pymod = PyImport_Import(pyplotname); - Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } - - PyObject * mpl_toolkitsmod; - PyObject * axis3dmod; - 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!"); } - } - - - - - - - - - - - - - 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"); -#endif - s_python_empty_tuple = PyTuple_New(0); + 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()); + } + + pymod = PyImport_Import(pyplotname); + Py_DECREF(pyplotname); + if (!pymod) { + throw std::runtime_error("Error loading module matplotlib.pyplot!"); + } + + PyObject *mpl_toolkitsmod; + PyObject *axis3dmod; + 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!"); + } + } + + s_python_colormap = PyImport_Import(cmname); + Py_DECREF(cmname); + if (!s_python_colormap) { + throw std::runtime_error("Error loading module matplotlib.cm!"); } - ~_interpreter() { - Py_Finalize(); + 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"); +#endif + s_python_empty_tuple = PyTuple_New(0); + } + + ~_interpreter() { Py_Finalize(); } }; } // end namespace detail @@ -3341,141 +324,163 @@ struct _interpreter { /// 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; -} +/// 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; } -PyObject * chart(int place) -{ - PyObject * drawObject = PyObject_GetAttrString(detail::_interpreter::get().pymod, "subplot"); - PyObject * args = PyTuple_New(1); - PyObject * kwargs = PyDict_New(); - PyTuple_SetItem(args, 0, PyLong_FromLong(place)); - PyDict_SetItemString(kwargs, "projection", PyUnicode_FromString("3d")); - PyObject * thePlot = PyObject_Call(drawObject, args, kwargs); - return thePlot; +PyObject *chart(int place) { + PyObject *drawObject = + PyObject_GetAttrString(detail::_interpreter::get().pymod, "subplot"); + PyObject *args = PyTuple_New(1); + PyObject *kwargs = PyDict_New(); + PyTuple_SetItem(args, 0, PyLong_FromLong(place)); + PyDict_SetItemString(kwargs, "projection", PyUnicode_FromString("3d")); + PyObject *thePlot = PyObject_Call(drawObject, args, kwargs); + return thePlot; } -inline void Clear3DChart(PyObject * ax) -{ - PyObject * eraser = PyObject_GetAttrString(ax, "cla"); - PyObject * args = PyTuple_New(0); - PyObject_CallObject(eraser, args); +inline void Clear3DChart(PyObject *ax) { + PyObject *eraser = PyObject_GetAttrString(ax, "cla"); + PyObject *args = PyTuple_New(0); + PyObject_CallObject(eraser, args); } 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 +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; }; +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; - } +template <> struct select_npy_type { + const static NPY_TYPES type = NPY_UINT64; +}; - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); +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()); +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())); } @@ -3483,10 +488,9 @@ inline PyObject * get_array(const std::vector& strings) } // 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()); +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])); } @@ -3498,64 +502,63 @@ PyObject* get_listlist(const std::vector>& ll) /// 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()); +template +bool plot(const std::vector &x, const std::vector &y, + const std::map &keywords) { + assert(x.size() == y.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::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(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, 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(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_plot, args, kwargs); - return res; + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; } // TODO - it should be possible to make this work by implementing // a non-numpy alternative for `detail::get_2darray()`. #ifndef WITHOUT_NUMPY template -void surface3D(PyObject * ax, - const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - std::string color, - double linewidth) -{ - PyObject * X = detail::get_2darray(x); - PyObject * Y = detail::get_2darray(y); - PyObject * Z = detail::get_2darray(z); - - PyObject * args = PyTuple_New(3); - PyObject * kwargs = PyDict_New(); - PyTuple_SetItem(args, 0, X); - PyTuple_SetItem(args, 1, Y); - PyTuple_SetItem(args, 2, Z); - PyDict_SetItemString(kwargs, "color", PyUnicode_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "linewidth", PyLong_FromLong(linewidth)); - - - PyObject * thePlot = PyObject_GetAttrString(ax, "plot_surface"); - PyObject_Call(thePlot, args, kwargs); +void surface3D(PyObject *ax, const std::vector<::std::vector> &x, + const std::vector<::std::vector> &y, + const std::vector<::std::vector> &z, std::string color, + double linewidth) { + PyObject *X = detail::get_2darray(x); + PyObject *Y = detail::get_2darray(y); + PyObject *Z = detail::get_2darray(z); + + PyObject *args = PyTuple_New(3); + PyObject *kwargs = PyDict_New(); + PyTuple_SetItem(args, 0, X); + PyTuple_SetItem(args, 1, Y); + PyTuple_SetItem(args, 2, Z); + PyDict_SetItemString(kwargs, "color", PyUnicode_FromString(color.c_str())); + PyDict_SetItemString(kwargs, "linewidth", PyLong_FromLong(linewidth)); + + PyObject *thePlot = PyObject_GetAttrString(ax, "plot_surface"); + PyObject_Call(thePlot, args, kwargs); } template @@ -3564,8 +567,7 @@ void plot_surface(const std::vector<::std::vector> &x, const std::vector<::std::vector> &z, const std::map &keywords = std::map(), - const long fig_number=0) -{ + const long fig_number = 0) { detail::_interpreter::get(); // We lazily load the modules here the first time this function is called @@ -3576,17 +578,23 @@ void plot_surface(const std::vector<::std::vector> &x, 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"); } + 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!"); } + 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!"); } + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } } assert(x.size() == y.size()); @@ -3617,63 +625,68 @@ void plot_surface(const std::vector<::std::vector> &x, it != keywords.end(); ++it) { if (it->first == "linewidth" || it->first == "alpha") { PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); + PyFloat_FromDouble(std::stod(it->second))); } else { PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); + PyString_FromString(it->second.c_str())); } } PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; + 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); + 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); + 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); + 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."); + 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"); + 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"); + 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"); + 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"); + 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); + 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 = {}) -{ + const std::map &keywords = {}) { detail::_interpreter::get(); // using numpy arrays @@ -3701,20 +714,21 @@ void contour(const std::vector<::std::vector> &x, PyString_FromString(it->second.c_str())); } - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs); + 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); + 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 = {}) -{ + const double markersize = -1, // -1 for default matplotlib size + const std::map &keywords = {}) { detail::_interpreter::get(); PyObject *xarray = detail::get_2darray(x); @@ -3737,18 +751,85 @@ void spy(const std::vector<::std::vector> &x, Py_DECREF(plot_args); Py_DECREF(kwargs); - if (res) Py_DECREF(res); + 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) -{ +void axis_equal(const std::vector &x, const std::vector &y, + const std::vector &z, const long fig_number = 0) { + + // get axis + 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"); + + // get axis limit objects + PyObject *xlim = PyObject_GetAttrString(axis, "set_xlim"); + PyObject *ylim = PyObject_GetAttrString(axis, "set_ylim"); + PyObject *zlim = PyObject_GetAttrString(axis, "set_zlim"); + + // calculate limits + double minX = *std::min_element(x.begin(), x.end()); + double maxX = *std::max_element(x.begin(), x.end()); + double minY = *std::min_element(y.begin(), y.end()); + double maxY = *std::max_element(y.begin(), y.end()); + double minZ = *std::min_element(z.begin(), z.end()); + double maxZ = *std::max_element(z.begin(), z.end()); + double max_range = + std::max({(maxX - minX), (maxY - minY), (maxZ - minZ)}) / 2.0; + double mid_x = (x.back() + x.front()) * 0.5; + double mid_y = (y.back() + y.front()) * 0.5; + double mid_z = (z.back() + z.front()) * 0.5; + + // set limits + PyObject *xlim_args = PyTuple_New(2); + PyObject *ylim_args = PyTuple_New(2); + PyObject *zlim_args = PyTuple_New(2); + PyTuple_SetItem(xlim_args, 0, PyFloat_FromDouble(mid_x - 1.2 * max_range)); + PyTuple_SetItem(xlim_args, 1, PyFloat_FromDouble(mid_x + 1.2 * max_range)); + PyTuple_SetItem(ylim_args, 0, PyFloat_FromDouble(mid_y - 1.2 * max_range)); + PyTuple_SetItem(ylim_args, 1, PyFloat_FromDouble(mid_y + 1.2 * max_range)); + PyTuple_SetItem(zlim_args, 0, PyFloat_FromDouble(mid_z - 1.2 * max_range)); + PyTuple_SetItem(zlim_args, 1, PyFloat_FromDouble(mid_z + 1.2 * max_range)); + + PyObject_CallObject(xlim, xlim_args); + PyObject_CallObject(ylim, ylim_args); + PyObject_CallObject(zlim, zlim_args); +} + +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 @@ -3759,17 +840,23 @@ void plot3(const std::vector &x, 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"); } + 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!"); } + 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!"); } + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } } assert(x.size() == y.size()); @@ -3795,384 +882,415 @@ void plot3(const std::vector &x, } PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; + 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); + 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); + 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); + fig = PyObject_CallObject( + detail::_interpreter::get().s_python_function_figure, fig_args); } - if (!fig) throw std::runtime_error("Call to figure() failed."); + 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"); + 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"); + 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"); + 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"); + 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); + 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()); +template +bool stem(const std::vector &x, const std::vector &y, + const std::map &keywords) { + assert(x.size() == y.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::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(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, 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(args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_stem, args, kwargs); - return res; + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); + + return res; } -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -{ - assert(x.size() == y.size()); +template +bool fill(const std::vector &x, const std::vector &y, + const std::map &keywords) { + assert(x.size() == y.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); + // using numpy arrays + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } + // construct positional args + PyObject *args = PyTuple_New(2); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs); + // 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())); + } - Py_DECREF(args); - Py_DECREF(kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_fill, args, kwargs); - if (res) Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(kwargs); - return res; + if (res) + Py_DECREF(res); + + return res; } -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()); +template +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(); + detail::_interpreter::get(); - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* y1array = detail::get_array(y1); - PyObject* y2array = detail::get_array(y2); + // 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())); - } + // 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); + 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); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - return 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); +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); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(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)); - return res; -} + 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); -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(); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); - PyObject* yarray = detail::get_array(y); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - 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); + return res; +} + +template +bool hist(const std::vector &y, long bins = 10, + std::string color = "b", double alpha = 1.0, + bool cumulative = false) { + detail::_interpreter::get(); - PyObject* plot_args = PyTuple_New(1); + PyObject *yarray = detail::get_array(y); - PyTuple_SetItem(plot_args, 0, yarray); + 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(1); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); + 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); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - return res; + return res; } #ifndef WITHOUT_NUMPY namespace detail { -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); +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(); + 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 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())); - } + // 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); + 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 -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); +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); } -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); +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); } #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())); - } +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); - } + // 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); + detail::imshow(image2.data, npy_type, image2.rows, image2.cols, + image2.channels(), keywords); } #endif // WITH_OPENCV #endif // WITHOUT_NUMPY -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(); +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(); - assert(x.size() == y.size()); + assert(x.size() == y.size()); - 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* 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 *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); + 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); + 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); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - return 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(); +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(); + + assert(x.size() == y.size()); - assert(x.size() == y.size()); + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); + PyObject *colors_array = detail::get_array(colors); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* colors_array = detail::get_array(colors); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); + PyDict_SetItemString(kwargs, "c", colors_array); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - PyDict_SetItemString(kwargs, "c", colors_array); + for (const auto &it : keywords) { + PyDict_SetItemString(kwargs, it.first.c_str(), + PyString_FromString(it.second.c_str())); + } - 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); - 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); - 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); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + return 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) { +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 + // 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"); } + 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!"); } + 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!"); } + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } } assert(x.size() == y.size()); @@ -4197,377 +1315,402 @@ bool scatter(const std::vector& x, PyString_FromString(it->second.c_str())); } PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; + 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); + 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); + 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); + 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."); + 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"); + 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"); + 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"); + 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"); + 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); + 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(); +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 *listlist = detail::get_listlist(data); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, listlist); - PyObject* kwargs = PyDict_New(); + PyObject *kwargs = PyDict_New(); - // 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)); - } + // 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)); + } - // take care of the remaining keywords - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } + // take care of the remaining keywords + for (const auto &it : keywords) { + PyDict_SetItemString(kwargs, it.first.c_str(), + PyString_FromString(it.second.c_str())); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_boxplot, 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; } -template -bool boxplot(const std::vector& data, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); +template +bool boxplot(const std::vector &data, + const std::map &keywords = {}) { + detail::_interpreter::get(); - PyObject* vector = detail::get_array(data); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, vector); + PyObject *vector = detail::get_array(data); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, vector); - PyObject* kwargs = PyDict_New(); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } + PyObject *kwargs = PyDict_New(); + for (const auto &it : keywords) { + PyDict_SetItemString(kwargs, it.first.c_str(), + PyString_FromString(it.second.c_str())); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_boxplot, 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; } 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 = {}) -{ +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 *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - PyObject * kwargs = PyDict_New(); + 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())); + 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); + 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); + 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); + 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 = {}) -{ +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); } + 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); -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(); + 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)); + 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())); - } + 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 *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); + 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); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - return res; + return res; } +inline bool +subplots_adjust(const std::map &keywords = {}) { + detail::_interpreter::get(); -inline bool subplots_adjust(const std::map& keywords = {}) -{ - 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 *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 *plot_args = PyTuple_New(0); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); + 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); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - return res; + return res; } -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* yarray = detail::get_array(y); +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* 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 *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 *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); + 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); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); - return res; + return res; } -template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); +template +bool plot(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_plot, plot_args); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_plot, 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 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()); +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 *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); + 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())); - } + // 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); + 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); + 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& u, const std::vector& w, const std::map& keywords = {}) -{ - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); +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(); + 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 *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 *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); - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_quiver, plot_args, 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(), + PyUnicode_FromString(it->second.c_str())); + } - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); - return res; + 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& z, const std::vector& u, const std::vector& w, const std::vector& v, const std::map& keywords = {}) -{ - //set up 3d axes stuff +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"); } + 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!"); } + 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!"); } + 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 + // 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 *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); + PyObject *plot_args = PyTuple_New(6); PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, zarray); @@ -4576,1496 +1719,1601 @@ bool quiver(const std::vector& x, const std::vector& y, cons 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())); + 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 + + // 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."); + 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"); + 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"); + 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 + + // 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"); + 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"); + 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); + 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 stem(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_stem, plot_args); + 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(); + detail::_interpreter::get(); - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* yerrarray = detail::get_array(yerr); + 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())); - } + // 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); + PyDict_SetItemString(kwargs, "yerr", yerrarray); - PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); + PyObject *res = + PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, + plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); + Py_DECREF(kwargs); + Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - else - throw std::runtime_error("Call to errorbar() failed."); + if (res) + Py_DECREF(res); + else + throw std::runtime_error("Call to errorbar() failed."); - return res; + return res; } -template -bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); +template +bool named_plot(const std::string &name, const std::vector &y, + const std::string &format = "") { + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - PyObject* yarray = detail::get_array(y); + PyObject *yarray = detail::get_array(y); - PyObject* pystring = PyString_FromString(format.c_str()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* plot_args = PyTuple_New(2); + PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, yarray); - PyTuple_SetItem(plot_args, 1, pystring); + PyTuple_SetItem(plot_args, 0, yarray); + PyTuple_SetItem(plot_args, 1, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; + return res; } -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); +template +bool named_plot(const std::string &name, const std::vector &x, + const std::vector &y, + const std::string &format = "") { + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - 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(format.c_str()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; + return res; } -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); +template +bool named_semilogx(const std::string &name, const std::vector &x, + const std::vector &y, + const std::string &format = "") { + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - 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(format.c_str()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + PyObject *res = + PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, + plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; + return res; } -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); +template +bool named_semilogy(const std::string &name, const std::vector &x, + const std::vector &y, + const std::string &format = "") { + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - 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(format.c_str()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + PyObject *res = + PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, + plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; + return res; } -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); +template +bool named_loglog(const std::string &name, const std::vector &x, + const std::vector &y, + const std::string &format = "") { + detail::_interpreter::get(); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - 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(format.c_str()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); + Py_DECREF(kwargs); + Py_DECREF(plot_args); + if (res) + Py_DECREF(res); - return res; + return res; } -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::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); } -template -bool plot(const std::vector& y, const std::map& keywords) -{ - 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 < x.size(); ++i) + x.at(i) = i; + return plot(x, y, keywords); } -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); +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); } -template -void text(Numeric x, Numeric y, const std::string& s = "") -{ - detail::_interpreter::get(); +template +void text(Numeric x, Numeric y, const std::string &s = "") { + 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(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* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); - if(!res) throw std::runtime_error("Call to text() failed."); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_text, args); + if (!res) + throw std::runtime_error("Call to text() failed."); - Py_DECREF(args); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(res); } -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."); +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."); - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, mappable); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, mappable); - 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 *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* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); - if(!res) throw std::runtime_error("Call to colorbar() failed."); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_colorbar, args, kwargs); + if (!res) + throw std::runtime_error("Call to colorbar() failed."); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } +inline long figure(long number = -1) { + detail::_interpreter::get(); -inline long figure(long number = -1) -{ - detail::_interpreter::get(); - - 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 *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); - // Make sure interpreter is initialised - detail::_interpreter::get(); + // Make sure interpreter is initialised + 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); - Py_DECREF(args); - } + 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); + } - if(!res) throw std::runtime_error("Call to figure() failed."); + 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); + 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); - Py_DECREF(num); - Py_DECREF(res); + Py_DECREF(num); + Py_DECREF(res); - return figureNumber; + return figureNumber; } -inline bool fignum_exists(long number) -{ - detail::_interpreter::get(); +inline bool fignum_exists(long number) { + detail::_interpreter::get(); - 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."); + 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."); - bool ret = PyObject_IsTrue(res); - Py_DECREF(res); - Py_DECREF(args); + bool ret = PyObject_IsTrue(res); + Py_DECREF(res); + Py_DECREF(args); - return ret; + return ret; } -inline void figure_size(size_t w, size_t h) -{ - detail::_interpreter::get(); +inline void figure_size(size_t w, size_t h) { + detail::_interpreter::get(); - 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)); + 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)); - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "figsize", size); - PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); + PyObject *kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "figsize", size); + PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + PyObject *res = + PyObject_Call(detail::_interpreter::get().s_python_function_figure, + detail::_interpreter::get().s_python_empty_tuple, kwargs); - Py_DECREF(kwargs); + Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to figure_size() failed."); - Py_DECREF(res); + if (!res) + throw std::runtime_error("Call to figure_size() failed."); + Py_DECREF(res); } -inline void legend() -{ - detail::_interpreter::get(); +inline void legend() { + 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 *res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, + detail::_interpreter::get().s_python_empty_tuple); + if (!res) + throw std::runtime_error("Call to legend() failed."); - Py_DECREF(res); + Py_DECREF(res); } -inline void legend(const std::map& keywords) -{ +inline void legend(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())); + 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(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."); + 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(kwargs); Py_DECREF(res); } -template -inline void set_aspect(Numeric ratio) -{ - detail::_interpreter::get(); +template inline void set_aspect(Numeric ratio) { + detail::_interpreter::get(); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(ratio)); - 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); } -inline void set_aspect_equal() -{ - // expect ratio == "equal". Leaving error handling to matplotlib. - 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 *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 *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(); +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); -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."); + if (!res) + throw std::runtime_error("Call to xlim() failed."); - Py_DECREF(res); + Py_DECREF(res); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; + PyObject *left = PyTuple_GetItem(res, 0); + PyObject *right = PyTuple_GetItem(res, 1); + return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; } +inline std::array ylim() { + PyObject *args = PyTuple_New(0); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_ylim, args); -inline std::array ylim() -{ - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - - if(!res) throw std::runtime_error("Call to ylim() failed."); + if (!res) + throw std::runtime_error("Call to ylim() failed."); - Py_DECREF(res); + Py_DECREF(res); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; + PyObject *left = PyTuple_GetItem(res, 0); + PyObject *right = PyTuple_GetItem(res, 1); + return {PyFloat_AsDouble(left), PyFloat_AsDouble(right)}; } -template -inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); +template +inline void xticks(const std::vector &ticks, + const std::vector &labels = {}, + const std::map &keywords = {}) { + assert(labels.size() == 0 || ticks.size() == labels.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); + // using numpy array + PyObject *ticksarray = detail::get_array(ticks); - 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); - } + 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 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 + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, ticksarray); + PyTuple_SetItem(args, 1, labelstuple); + } + + // 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(detail::_interpreter::get().s_python_function_xticks, args, kwargs); + 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"); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to xticks() failed"); - Py_DECREF(res); + Py_DECREF(res); } -template -inline void xticks(const std::vector &ticks, const std::map& keywords) -{ - xticks(ticks, {}, keywords); +template +inline void xticks(const std::vector &ticks, + const std::map &keywords) { + xticks(ticks, {}, keywords); } -template -inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); +template +inline void yticks(const std::vector &ticks, + const std::vector &labels = {}, + const std::map &keywords = {}) { + assert(labels.size() == 0 || ticks.size() == labels.size()); - detail::_interpreter::get(); + detail::_interpreter::get(); - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); + // using numpy array + PyObject *ticksarray = detail::get_array(ticks); - 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); - } + 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 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 + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, ticksarray); + PyTuple_SetItem(args, 1, labelstuple); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, 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(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to yticks() failed"); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_yticks, args, kwargs); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to yticks() failed"); + + Py_DECREF(res); } -template -inline void yticks(const std::vector &ticks, const std::map& keywords) -{ - yticks(ticks, {}, keywords); +template +inline void yticks(const std::vector &ticks, + const std::map &keywords) { + yticks(ticks, {}, keywords); } -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) { + // construct positional args + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); - PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_margins, args); + if (!res) + throw std::runtime_error("Call to margins() failed."); - Py_DECREF(args); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(res); } -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)); +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_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_margins, args); + 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") -{ +inline void tick_params(const std::map &keywords, + const std::string axis = "both") { detail::_interpreter::get(); // construct positional args - PyObject* args; + PyObject *args; args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyString_FromString(axis.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(), PyString_FromString(it->second.c_str())); + 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(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); + 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"); + if (!res) + throw std::runtime_error("Call to tick_params() failed"); Py_DECREF(res); } -inline void subplot(long nrows, long ncols, long plot_number) -{ - detail::_interpreter::get(); +inline void subplot(long nrows, long ncols, long plot_number) { + detail::_interpreter::get(); - // 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)); + // 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_CallObject( + detail::_interpreter::get().s_python_function_subplot, args); + if (!res) + throw std::runtime_error("Call to subplot() failed."); - Py_DECREF(args); - Py_DECREF(res); + 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 subplot2grid(long nrows, long ncols, long rowid = 0, long colid = 0, + long rowspan = 1, long colspan = 1) { + detail::_interpreter::get(); - PyObject* shape = PyTuple_New(2); - PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); - PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); + PyObject *shape = PyTuple_New(2); + PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); + PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); - PyObject* loc = PyTuple_New(2); - PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); - PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); + PyObject *loc = PyTuple_New(2); + PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); + PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); - 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 *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_subplot2grid, args); - if(!res) throw std::runtime_error("Call to subplot2grid() 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(shape); - Py_DECREF(loc); - Py_DECREF(args); - Py_DECREF(res); + Py_DECREF(shape); + Py_DECREF(loc); + Py_DECREF(args); + Py_DECREF(res); } -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); +inline void title(const std::string &titlestr, + const std::map &keywords = {}) { + detail::_interpreter::get(); - PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pytitlestr); + 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 *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(detail::_interpreter::get().s_python_function_title, args, kwargs); - if(!res) throw std::runtime_error("Call to title() failed."); + 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); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); +inline void suptitle(const std::string &suptitlestr, + const std::map &keywords = {}) { + detail::_interpreter::get(); - PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pysuptitlestr); + PyObject *pysuptitlestr = PyString_FromString(suptitlestr.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pysuptitlestr); - 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 *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(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); - if(!res) throw std::runtime_error("Call to suptitle() failed."); + 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); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } -inline void axis(const std::string &axisstr) -{ - detail::_interpreter::get(); +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); + PyObject *str = PyString_FromString(axisstr.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, str); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_axis, args); + if (!res) + throw std::runtime_error("Call to title() failed."); - Py_DECREF(args); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(res); } -inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); +inline void axhline(double y, double xmin = 0., double xmax = 1., + const std::map &keywords = + std::map()) { + detail::_interpreter::get(); - // 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)); - - // 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(y)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmin)); + PyTuple_SetItem(args, 2, PyFloat_FromDouble(xmax)); + + // 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(detail::_interpreter::get().s_python_function_axhline, args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_axhline, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) + Py_DECREF(res); } -inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); +inline void axvline(double x, double ymin = 0., double ymax = 1., + const std::map &keywords = + std::map()) { + detail::_interpreter::get(); - // 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)); - - // 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(x)); + PyTuple_SetItem(args, 1, PyFloat_FromDouble(ymin)); + PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymax)); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, 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(args); - Py_DECREF(kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_axvline, args, kwargs); + + Py_DECREF(args); + Py_DECREF(kwargs); - if(res) Py_DECREF(res); + 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)); - - // 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())); - } +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); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_axvspan, args, kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) + Py_DECREF(res); } -inline void xlabel(const std::string &str, const std::map &keywords = {}) -{ - detail::_interpreter::get(); +inline void xlabel(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); + PyObject *pystr = PyString_FromString(str.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); - 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 *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(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_xlabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to xlabel() failed."); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); + 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 ylabel(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); + PyObject *pystr = PyString_FromString(str.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); - 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 *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(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); - if(!res) throw std::runtime_error("Call to ylabel() failed."); + 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); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } -inline void set_zlabel(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(); - // 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"); } + // 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!"); } + 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!"); } + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } + } - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); + PyObject *pystr = PyString_FromString(str.c_str()); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pystr); - 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 *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 *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 *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); - if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); - Py_INCREF(zlabel); + PyObject *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); + if (!zlabel) + throw std::runtime_error("Attribute set_zlabel not found."); + Py_INCREF(zlabel); - PyObject *res = PyObject_Call(zlabel, args, kwargs); - if (!res) throw std::runtime_error("Call to set_zlabel() failed."); - Py_DECREF(zlabel); + PyObject *res = PyObject_Call(zlabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to set_zlabel() failed."); + Py_DECREF(zlabel); - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + Py_DECREF(ax); + Py_DECREF(args); + Py_DECREF(kwargs); + if (res) + Py_DECREF(res); } -inline void grid(bool flag) -{ - detail::_interpreter::get(); +inline void grid(bool flag) { + detail::_interpreter::get(); - PyObject* pyflag = flag ? Py_True : Py_False; - Py_INCREF(pyflag); + PyObject *pyflag = flag ? Py_True : Py_False; + Py_INCREF(pyflag); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyflag); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyflag); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_grid, args); + if (!res) + throw std::runtime_error("Call to grid() failed."); - Py_DECREF(args); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(res); } -inline void show(const bool block = true) -{ - 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); - } +inline void show(const bool block = true) { + 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( - detail::_interpreter::get().s_python_function_close, - detail::_interpreter::get().s_python_empty_tuple); + 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."); + if (!res) + throw std::runtime_error("Call to close() failed."); - Py_DECREF(res); + Py_DECREF(res); } inline void xkcd() { - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* res; - PyObject *kwargs = PyDict_New(); + PyObject *res; + PyObject *kwargs = PyDict_New(); - res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, + detail::_interpreter::get().s_python_empty_tuple, kwargs); - Py_DECREF(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 draw() -{ - detail::_interpreter::get(); +inline void draw() { + detail::_interpreter::get(); - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_draw, - detail::_interpreter::get().s_python_empty_tuple); + PyObject *res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_draw, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to draw() failed."); + if (!res) + throw std::runtime_error("Call to draw() failed."); - Py_DECREF(res); + Py_DECREF(res); } -template -inline void pause(Numeric interval) -{ - detail::_interpreter::get(); +template inline void pause(Numeric interval) { + detail::_interpreter::get(); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); - if(!res) throw std::runtime_error("Call to pause() failed."); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_pause, args); + if (!res) + throw std::runtime_error("Call to pause() failed."); - Py_DECREF(args); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(res); } -inline void save(const std::string& filename, const int dpi=0) -{ - detail::_interpreter::get(); +inline void save(const std::string &filename, const int dpi = 0) { + detail::_interpreter::get(); - PyObject* pyfilename = PyString_FromString(filename.c_str()); + PyObject *pyfilename = PyString_FromString(filename.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyfilename); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pyfilename); - PyObject* kwargs = PyDict_New(); + PyObject *kwargs = PyDict_New(); - if(dpi > 0) - { - PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); - } + if (dpi > 0) { + PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_save, args, kwargs); - if (!res) throw std::runtime_error("Call to save() 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(args); - Py_DECREF(kwargs); - Py_DECREF(res); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(res); } -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 * 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 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 *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(); + detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); + PyObject *res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_clf, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to clf() failed."); + if (!res) + throw std::runtime_error("Call to clf() failed."); - Py_DECREF(res); + Py_DECREF(res); } inline void cla() { - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, - detail::_interpreter::get().s_python_empty_tuple); + PyObject *res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) - throw std::runtime_error("Call to cla() failed."); + if (!res) + throw std::runtime_error("Call to cla() failed."); - Py_DECREF(res); + Py_DECREF(res); } inline void ion() { - detail::_interpreter::get(); + detail::_interpreter::get(); - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - 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 ion() failed."); + if (!res) + throw std::runtime_error("Call to ion() failed."); - Py_DECREF(res); + Py_DECREF(res); } -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ - detail::_interpreter::get(); +inline std::vector> +ginput(const int numClicks = 1, + const std::map &keywords = {}) { + detail::_interpreter::get(); - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); - // 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())); - } + // 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_ginput, args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_ginput, args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(args); - if (!res) throw std::runtime_error("Call to ginput() 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(kwargs); + Py_DECREF(args); + if (!res) + throw std::runtime_error("Call to ginput() 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); - return out; + return out; } // Actually, is there any reason not to call this automatically for every plot? inline void tight_layout() { - detail::_interpreter::get(); + 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_tight_layout, + 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 tight_layout() failed."); - Py_DECREF(res); + Py_DECREF(res); } // Support for variadic plot() and initializer lists: namespace detail { -template -using is_function = typename std::is_function>>::type; +template +using is_function = typename std::is_function< + std::remove_pointer>>::type; -template -struct is_callable_impl; +template struct is_callable_impl; -template -struct is_callable_impl -{ - typedef is_function type; +template struct is_callable_impl { + typedef is_function type; }; // a non-object is callable iff it is a function -template -struct is_callable_impl -{ - struct Fallback { void operator()(); }; - struct Derived : T, Fallback { }; +template struct is_callable_impl { + struct Fallback { + void operator()(); + }; + struct Derived : T, Fallback {}; - template struct Check; + 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::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* ); + template + static std::false_type test(Check *); public: - typedef decltype(test(nullptr)) type; - typedef decltype(&Fallback::operator()) dtype; - static constexpr bool value = type::value; + 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; +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; }; -template -struct plot_impl { }; +template struct plot_impl {}; -template<> -struct plot_impl -{ - template - bool operator()(const IterableX& x, const IterableY& y, const std::string& format) - { - detail::_interpreter::get(); +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::distance; - using std::begin; - using std::end; + // 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!"); + 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()); + 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++)); - } + 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 *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); + PyObject *res = PyObject_CallObject( + detail::_interpreter::get().s_python_function_plot, 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<> -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); - } +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() { 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 +bool plot(const A &a, const B &b, const std::string &format, Args... args) { + return detail::plot_impl::type>()(a, b, + format) && + plot(args...); } /* - * This group of plot() functions is needed to support initializer lists, i.e. calling - * plot( {1,2,3,4} ) + * 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); +inline bool plot(const std::vector &x, const std::vector &y, + const std::string &format = "") { + return plot(x, y, format); } -inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(y,format); +inline bool plot(const std::vector &y, const std::string &format = "") { + return plot(y, format); } -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); +inline bool plot(const std::vector &x, const std::vector &y, + const std::map &keywords) { + return plot(x, y, keywords); } /* - * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting + * This class allows dynamic plots, ie changing the plotted data without + * clearing and re-plotting */ -class Plot -{ +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(); + // 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(); - assert(x.size() == y.size()); + assert(x.size() == y.size()); - PyObject* kwargs = PyDict_New(); - if(name != "") - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + PyObject *kwargs = PyDict_New(); + if (name != "") + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - 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(format.c_str()); + PyObject *pystring = PyString_FromString(format.c_str()); - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); + PyObject *plot_args = PyTuple_New(3); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject *res = PyObject_Call( + detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(plot_args); + Py_DECREF(kwargs); + Py_DECREF(plot_args); - if(res) - { - line= PyList_GetItem(res, 0); + if (res) { + line = PyList_GetItem(res, 0); - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); - else - Py_DECREF(line); - Py_DECREF(res); - } + if (line) + set_data_fct = PyObject_GetAttrString(line, "set_data"); + else + Py_DECREF(line); + Py_DECREF(res); } + } - // 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) - { - 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) {} - // clears the plot but keep it available - bool clear() { - return update(std::vector(), std::vector()); - } + template + bool update(const std::vector &x, const std::vector &y) { + assert(x.size() == y.size()); + if (set_data_fct) { + PyObject *xarray = detail::get_array(x); + PyObject *yarray = detail::get_array(y); - // definitely remove this line - void remove() { - 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(); - } + PyObject *plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); - ~Plot() { - decref(); + PyObject *res = PyObject_CallObject(set_data_fct, plot_args); + if (res) + Py_DECREF(res); + return res; } -private: + return false; + } - void decref() { - if(line) - Py_DECREF(line); - if(set_data_fct) - Py_DECREF(set_data_fct); + // clears the plot but keep it available + bool clear() { return update(std::vector(), std::vector()); } + + // definitely remove this line + void remove() { + 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(); + } + + ~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 \ No newline at end of file