diff --git a/.gitignore b/.gitignore index 1c4a1b0..2c511cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +#Clean Repo +cmake +contrib +example +*.yml +*.txt +LICENSE* + # Compiled Object files *.slo *.lo 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 deleted file mode 100644 index bb2decd..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,133 +0,0 @@ -cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -project(matplotlib_cpp LANGUAGES CXX) - -include(GNUInstallDirs) -set(PACKAGE_NAME matplotlib_cpp) -set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/${PACKAGE_NAME}/cmake) - - -# 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 -) - - -# Examples -add_executable(minimal examples/minimal.cpp) -target_link_libraries(minimal PRIVATE matplotlib_cpp) -set_target_properties(minimal PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -add_executable(basic examples/basic.cpp) -target_link_libraries(basic PRIVATE matplotlib_cpp) -set_target_properties(basic PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -add_executable(modern examples/modern.cpp) -target_link_libraries(modern PRIVATE matplotlib_cpp) -set_target_properties(modern PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -add_executable(animation examples/animation.cpp) -target_link_libraries(animation PRIVATE matplotlib_cpp) -set_target_properties(animation PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") - -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} -) 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..215af16 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,32 @@ -matplotlib-cpp -============== +# matplotlib-cpp Welcome to matplotlib-cpp, possibly the simplest C++ plotting library. It is built to resemble the plotting API used by Matlab and matplotlib. +## Usage + +Get the include directory and library path from following python script. + +```python +try: + from sysconfig import get_paths + import sys + dirs=get_paths() + lib=sys.version_info[0]+0.1*sys.version_info[1] + print("-I" + dirs['include']) + print("-L" + dirs['stdlib']+" -lpython"+str(lib) + " -Wl,-rpath,"+dirs['stdlib']) +except KeyError: + print("Not Found") + +try: + from numpy import get_include + print("-I"+get_include()) +except KeyError: + print("Not Found") +``` - -Usage ------ Complete minimal example: + ```cpp #include "matplotlibcpp.h" namespace plt = matplotlibcpp; @@ -17,6 +35,7 @@ int main() { plt::show(); } ``` + g++ minimal.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 **Result:** @@ -24,6 +43,7 @@ int main() { ![Minimal example](./examples/minimal.png) A more comprehensive example: + ```cpp #include "matplotlibcpp.h" #include @@ -59,6 +79,7 @@ int main() plt::save("./basic.png"); } ``` + g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 **Result:** @@ -66,6 +87,7 @@ int main() ![Basic example](./examples/basic.png) Alternatively, matplotlib-cpp also supports some C++11-powered syntactic sugar: + ```cpp #include #include "matplotlibcpp.h" @@ -94,13 +116,15 @@ int main() plt::show(); } ``` + g++ modern.cpp -std=c++11 -I/usr/include/python2.7 -lpython **Result:** ![Modern example](./examples/modern.png) -Or some *funny-looking xkcd-styled* example: +Or some _funny-looking xkcd-styled_ example: + ```cpp #include "matplotlibcpp.h" #include @@ -124,6 +148,7 @@ int main() { } ``` + g++ xkcd.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 **Result:** @@ -131,6 +156,7 @@ int main() { ![xkcd example](./examples/xkcd.png) When working with vector fields, you might be interested in quiver plots: + ```cpp #include "../matplotlibcpp.h" @@ -153,6 +179,7 @@ int main() plt::show(); } ``` + g++ quiver.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7 **Result:** @@ -160,6 +187,7 @@ int main() ![quiver example](./examples/quiver.png) When working with 3d functions, you might be interested in 3d plots: + ```cpp #include "../matplotlibcpp.h" @@ -189,8 +217,7 @@ int main() ![surface example](./examples/surface.png) -Installation ------------- +## 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. @@ -210,7 +237,6 @@ 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` @@ -219,7 +245,7 @@ has to be changed manually. (a PR that adds a cmake option for this would be hig 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 +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 @@ -240,9 +266,8 @@ You can download and install matplotlib-cpp using the [vcpkg](https://github.com ./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. +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 @@ -253,10 +278,8 @@ Note that support for c++98 was dropped more or less accidentally, so if you hav with an ancient compiler and still want to enjoy the latest additional features, I'd probably merge a PR that restores support. +## Why? - -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 @@ -274,21 +297,20 @@ 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 -Todo/Issues/Wishlist --------------------- -* This library is not thread safe. Protect all concurrent access with a mutex. +- 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 +- 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 +- 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 "".' +- 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). +- 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). 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; i -#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 be6af0f..0000000 Binary files a/examples/bar.png and /dev/null differ diff --git a/examples/basic.cpp b/examples/basic.cpp deleted file mode 100644 index 2dc34c7..0000000 --- a/examples/basic.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#define _USE_MATH_DEFINES -#include -#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; i -#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 aa1fc0d..0000000 Binary files a/examples/fill.png and /dev/null differ diff --git a/examples/fill_between.png b/examples/fill_between.png deleted file mode 100644 index a199423..0000000 Binary files a/examples/fill_between.png and /dev/null differ diff --git a/examples/fill_inbetween.cpp b/examples/fill_inbetween.cpp deleted file mode 100644 index 788d008..0000000 --- a/examples/fill_inbetween.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#define _USE_MATH_DEFINES -#include "../matplotlibcpp.h" -#include -#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 7a0c478..0000000 Binary files a/examples/lines3d.png and /dev/null differ diff --git a/examples/minimal.cpp b/examples/minimal.cpp deleted file mode 100644 index fbe1e1c..0000000 --- a/examples/minimal.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "../matplotlibcpp.h" - -namespace plt = matplotlibcpp; - -int main() { - plt::plot({1,3,2,4}); - plt::show(); -} diff --git a/examples/minimal.png b/examples/minimal.png deleted file mode 100644 index 0f6cf37..0000000 Binary files a/examples/minimal.png and /dev/null differ 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 -#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 9d7be1e..0000000 Binary files a/examples/quiver.png and /dev/null differ diff --git a/examples/spy.cpp b/examples/spy.cpp deleted file mode 100644 index 6027a48..0000000 --- a/examples/spy.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "../matplotlibcpp.h" - -#include -#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 6fc5fc7..0000000 Binary files a/examples/surface.png and /dev/null differ diff --git a/examples/update.cpp b/examples/update.cpp deleted file mode 100644 index 64f4906..0000000 --- a/examples/update.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#define _USE_MATH_DEFINES -#include -#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 c285e3d..0000000 Binary files a/examples/xkcd.png and /dev/null differ diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d95d46a..0d9cf77 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1,45 +1,46 @@ #pragma once - -// Python headers must be included before any system headers, since -// they define _POSIX_C_SOURCE +/***************************************************************** + Python headers must be included before any system headers, since + they define _POSIX_C_SOURCE +******************************************************************/ #include -#include -#include +#include #include +#include // requires c++11 support +#include +#include +#include #include -#include +#include #include -#include -#include // requires c++11 support -#include -#include // std::stod +#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 -#endif // WITHOUT_NUMPY +#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 { @@ -47,62 +48,62 @@ static std::string s_backend; struct _interpreter { PyObject* s_python_function_arrow; - PyObject *s_python_function_show; - PyObject *s_python_function_close; - PyObject *s_python_function_draw; - PyObject *s_python_function_pause; - PyObject *s_python_function_save; - PyObject *s_python_function_figure; - PyObject *s_python_function_fignum_exists; - PyObject *s_python_function_plot; - PyObject *s_python_function_quiver; + PyObject* s_python_function_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_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_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; + 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 @@ -112,31 +113,26 @@ struct _interpreter { 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 + 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& get() { return interkeeper(false); } - static _interpreter& kill() { - return interkeeper(true); - } + 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(); + 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 (!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.")); @@ -144,27 +140,25 @@ struct _interpreter { return fn; } -private: - + private: #ifndef WITHOUT_NUMPY -# if PY_MAJOR_VERSION >= 3 +#if PY_MAJOR_VERSION >= 3 - void *import_numpy() { - import_array(); // initialize C-API + void* import_numpy() { + import_array(); // initialize C-API return NULL; } -# else +#else void import_numpy() { - import_array(); // initialize C-API + import_array(); // initialize C-API } -# endif +#endif #endif _interpreter() { - // optional but recommended #if PY_MAJOR_VERSION >= 3 wchar_t name[] = L"plotting"; @@ -174,24 +168,29 @@ struct _interpreter { 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; + // Suppress Python warnings + PyRun_SimpleString("import warnings"); + PyRun_SimpleString("warnings.filterwarnings('ignore')"); + + 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"); + 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"); } @@ -207,89 +206,92 @@ struct _interpreter { // 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_CallMethod(matplotlib, const_cast("use"), const_cast("s"), + s_backend.c_str()); } - - PyObject* pymod = PyImport_Import(pyplotname); Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } + 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!"); } + 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"); + 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(); - } + ~_interpreter() { Py_Finalize(); } }; -} // end namespace detail +} // end namespace detail /// Select the backend /// @@ -300,20 +302,16 @@ struct _interpreter { /// 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 void backend(const std::string& name) { detail::s_backend = name; } -inline bool annotate(std::string annotation, double x, double y) -{ +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); @@ -321,12 +319,13 @@ inline bool annotate(std::string annotation, double x, double y) 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); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -335,36 +334,76 @@ 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; }; +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 <> +struct select_npy_type { + const static NPY_TYPES type = NPY_UINT64; +}; -template -PyObject* get_array(const std::vector& v) -{ +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(::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; @@ -374,73 +413,66 @@ PyObject* get_array(const std::vector& v) return varray; } - -template -PyObject* get_2darray(const std::vector<::std::vector>& v) -{ +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 +#else // fallback if we don't have numpy: copy every element of the given vector -template -PyObject* get_array(const std::vector& v) -{ +template +PyObject* get_array(const std::vector& v) { PyObject* list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { + for (size_t i = 0; i < v.size(); ++i) { PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); } return list; } -#endif // WITHOUT_NUMPY +#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; +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; +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 +} // 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) -{ +template +bool plot(const std::vector& x, const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -456,8 +488,8 @@ bool plot(const std::vector &x, const std::vector &y, const st // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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())); } @@ -465,7 +497,7 @@ bool plot(const std::vector &x, const std::vector &y, const st Py_DECREF(args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } @@ -474,286 +506,285 @@ bool plot(const std::vector &x, const std::vector &y, const st // 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))); +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 { - 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); + 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(); +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(); - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); + PyObject* python_colormap_coolwarm = + PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm"); - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - // 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 *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs); + if (!res) throw std::runtime_error("failed contour"); - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); + 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())); + } - 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_contour, args, kwargs); - if (!res) - throw std::runtime_error("failed contour"); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); } +#endif // WITHOUT_NUMPY 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(); +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); - PyObject *xarray = detail::get_2darray(x); + // Build up the kw args. + PyObject* kwargs = PyDict_New(); - 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())); - } + 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* 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 *res = PyObject_Call( - detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); + PyObject* gca_kwargs = PyDict_New(); + PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); + 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); } -#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) -{ +bool stem(const std::vector& x, const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -769,26 +800,23 @@ bool stem(const std::vector &x, const std::vector &y, const st // 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())); + 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); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_stem, args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -{ +template +bool fill(const std::vector& x, const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -818,16 +846,17 @@ bool fill(const std::vector& x, const std::vector& y, const st return res; } -template< typename Numeric > -bool fill_between(const std::vector& x, const std::vector& y1, const std::vector& y2, const std::map& keywords) -{ +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(); // using numpy arrays - PyObject* xarray = detail::get_array(x); + PyObject* xarray = detail::get_array(x); PyObject* y1array = detail::get_array(y1); PyObject* y2array = detail::get_array(y2); @@ -839,15 +868,17 @@ bool fill_between(const std::vector& x, const std::vector& y1, // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { + 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); + if (res) Py_DECREF(res); return res; } @@ -855,8 +886,8 @@ bool fill_between(const std::vector& x, const std::vector& y1, 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_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); @@ -873,20 +904,18 @@ bool arrow(Numeric x, Numeric y, Numeric end_x, Numeric end_y, const std::string PyTuple_SetItem(plot_args, 3, obj_end_y); PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); + PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if (res) - Py_DECREF(res); + 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) -{ +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* yarray = detail::get_array(y); @@ -901,13 +930,12 @@ bool hist(const std::vector& y, long bins=10,std::string color="b", 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); + if (res) Py_DECREF(res); return res; } @@ -915,86 +943,118 @@ bool hist(const std::vector& y, long bins=10,std::string color="b", #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 char order, const std::map& keywords, + PyObject** out) { + assert(type == NPY_UINT8 || type == NPY_FLOAT || type == NPY_DOUBLE); + assert(order == 'C' || order == 'c' || order == 'F' || order == 'f'); 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)); + npy_intp dims[2] = {rows, columns}; + PyObject* args = PyTuple_New(1); + if (order == 'F' || order == 'f') { + PyTuple_SetItem( + args, 0, + PyArray_New(&PyArray_Type, 2, dims, type, NULL, ptr, 0, NPY_ARRAY_FARRAY, NULL)); + } else { + PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(2, 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())); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { + if (it->first == "extent") { + std::string str = it->second; + if (str[0] == '(' && str.back() == ')') { + str.erase(0, 1); + str.erase(str.length() - 1, 1); + } + std::stringstream ss(str); + double ext[4]; + int i = 0; + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + ext[i] = std::stod(substr); + i++; + } + PyDict_SetItemString(kwargs, it->first.c_str(), + Py_BuildValue("(dddd)", ext[0], ext[1], ext[2], ext[3])); + } else { + 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); + 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 (!res) throw std::runtime_error("Call to imshow() failed"); if (out) *out = res; else Py_DECREF(res); } -} // namespace detail +} // 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 char order, + const std::map& keywords = {}, + PyObject** out = nullptr) { + detail::imshow((void*)ptr, NPY_UINT8, rows, columns, order, 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 char order, + const std::map& keywords = {}, + PyObject** out = nullptr) { + detail::imshow((void*)ptr, NPY_FLOAT, rows, columns, order, keywords, out); +} + +inline void imshow(const double* ptr, const int rows, const int columns, const char order, + const std::map& keywords = {}, + PyObject** out = nullptr) { + detail::imshow((void*)ptr, NPY_DOUBLE, rows, columns, order, keywords, out); } #ifdef WITH_OPENCV -void imshow(const cv::Mat &image, const std::map &keywords = {}) -{ +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())); + 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); + 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 +#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 = {}) -{ +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()); @@ -1004,8 +1064,7 @@ bool scatter(const std::vector& x, PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - for (const auto& it : keywords) - { + for (const auto& it : keywords) { PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); } @@ -1013,159 +1072,157 @@ bool scatter(const std::vector& x, 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); + 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(); +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())); + } + + 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(); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); + // Same as with plot_surface: We lazily load the modules here the first time + // this function is called because I'm not sure that we can assume "matplotlib + // installed" implies "mpl_toolkits installed" on all platforms, and we don't + // want to require it for people who don't need 3d plots. + static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; + if (!mpl_toolkitsmod) { + 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* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } + + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); + assert(x.size() == y.size()); + assert(y.size() == z.size()); - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + PyObject* zarray = detail::get_array(z); - return res; + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); + + // 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."); -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 + 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 = {}) -{ + const std::vector& labels = {}, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* listlist = detail::get_listlist(data); - PyObject* args = PyTuple_New(1); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, listlist); PyObject* kwargs = PyDict_New(); @@ -1176,126 +1233,119 @@ bool boxplot(const std::vector>& data, } // take care of the remaining keywords - for (const auto& it : 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); - if(res) Py_DECREF(res); + if (res) Py_DECREF(res); return res; } -template +template bool boxplot(const std::vector& data, - const std::map & keywords = {}) -{ + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* vector = detail::get_array(data); - PyObject* args = PyTuple_New(1); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, vector); PyObject* kwargs = PyDict_New(); - for (const auto& it : 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); - if(res) Py_DECREF(res); + 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(); +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)); + 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_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); + Py_DECREF(plot_args); + Py_DECREF(kwargs); + if (res) Py_DECREF(res); - return 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; +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(); + detail::_interpreter::get(); - std::vector x; - for (std::size_t i = 0; i < y.size(); i++) { x.push_back(i); } + 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); + 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)); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { + 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_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); @@ -1304,33 +1354,30 @@ bool barh(const std::vector &x, const std::vector &y, std::str return res; } - -inline bool subplots_adjust(const std::map& keywords = {}) -{ +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)); + 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); + 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); + 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) -{ +template +bool named_hist(std::string label, const std::vector& y, long bins = 10, + std::string color = "b", double alpha = 1.0) { detail::_interpreter::get(); PyObject* yarray = detail::get_array(y); @@ -1341,22 +1388,22 @@ bool named_hist(std::string label,const std::vector& y, long bins=10, s 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); + 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); + if (res) Py_DECREF(res); return res; } -template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool plot(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1371,10 +1418,11 @@ bool plot(const std::vector& x, const std::vector& y, const 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); + if (res) Py_DECREF(res); return res; } @@ -1402,19 +1450,19 @@ bool contour(const std::vector& x, const std::vector& y, } PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs); + PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) - Py_DECREF(res); + 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 = {}) -{ +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(); @@ -1432,111 +1480,117 @@ bool quiver(const std::vector& x, const std::vector& y, cons // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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); + 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); + 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 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 = "") -{ +template +bool stem(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1551,19 +1605,18 @@ bool stem(const std::vector& x, const std::vector& y, const 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); + if (res) Py_DECREF(res); return res; } -template -bool semilogx(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool semilogx(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1578,17 +1631,18 @@ bool semilogx(const std::vector& x, const std::vector& y, co 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); + if (res) Py_DECREF(res); return res; } -template -bool semilogy(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool semilogy(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1603,17 +1657,18 @@ bool semilogy(const std::vector& x, const std::vector& y, co 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); + if (res) Py_DECREF(res); return res; } -template -bool loglog(const std::vector& x, const std::vector& y, const std::string& s = "") -{ +template +bool loglog(const std::vector& x, const std::vector& y, + const std::string& s = "") { assert(x.size() == y.size()); detail::_interpreter::get(); @@ -1628,39 +1683,42 @@ bool loglog(const std::vector& x, const std::vector& y, cons 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); + 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 = {}) -{ +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* 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) - { + 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); + 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); @@ -1673,9 +1731,9 @@ bool errorbar(const std::vector &x, const std::vector &y, co return res; } -template -bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -{ +template +bool named_plot(const std::string& name, const std::vector& y, + const std::string& format = "") { detail::_interpreter::get(); PyObject* kwargs = PyDict_New(); @@ -1690,7 +1748,8 @@ bool named_plot(const std::string& name, const std::vector& y, const st 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); @@ -1699,9 +1758,9 @@ bool named_plot(const std::string& name, const std::vector& y, const st return res; } -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +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(); @@ -1717,7 +1776,8 @@ bool named_plot(const std::string& name, const std::vector& x, const s 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); @@ -1726,9 +1786,9 @@ bool named_plot(const std::string& name, const std::vector& x, const s return res; } -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +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(); @@ -1744,7 +1804,8 @@ bool named_semilogx(const std::string& name, const std::vector& x, con 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); @@ -1753,9 +1814,9 @@ bool named_semilogx(const std::string& name, const std::vector& x, con return res; } -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +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(); @@ -1771,7 +1832,8 @@ bool named_semilogy(const std::string& name, const std::vector& x, con 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); @@ -1780,9 +1842,9 @@ bool named_semilogy(const std::string& name, const std::vector& x, con return res; } -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ +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(); @@ -1797,7 +1859,8 @@ bool named_loglog(const std::string& name, const std::vector& x, const 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* res = + PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); @@ -1806,33 +1869,30 @@ bool named_loglog(const std::string& name, const std::vector& x, const return res; } -template -bool plot(const std::vector& y, const std::string& format = "") -{ +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) -{ +template +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 = "") -{ +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 = "") -{ +template +void text(Numeric x, Numeric y, const std::string& s, + const std::map& keywords = {}) { detail::_interpreter::get(); PyObject* args = PyTuple_New(3); @@ -1840,17 +1900,24 @@ void text(Numeric x, Numeric y, const std::string& s = "") 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* 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_text, args, kwargs); + if (!res) throw std::runtime_error("Call to text() failed."); Py_DECREF(args); + Py_DECREF(kwargs); Py_DECREF(res); } -inline void colorbar(PyObject* mappable = NULL, const std::map& keywords = {}) -{ +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."); + throw std::runtime_error( + "Must call colorbar with PyObject* returned from an image, contour, surface, etc."); detail::_interpreter::get(); @@ -1858,40 +1925,40 @@ inline void colorbar(PyObject* mappable = NULL, const std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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); } - -inline long figure(long number = -1) -{ +inline long figure(long number = -1) { detail::_interpreter::get(); - PyObject *res; + PyObject* res; if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); + 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); + 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"); @@ -1903,14 +1970,14 @@ inline long figure(long number = -1) return figureNumber; } -inline bool fignum_exists(long number) -{ +inline bool fignum_exists(long number) { detail::_interpreter::get(); - PyObject *args = PyTuple_New(1); + 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* 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); @@ -1919,12 +1986,11 @@ inline bool fignum_exists(long number) return ret; } -inline void figure_size(size_t w, size_t h) -{ +inline void figure_size(size_t w, size_t h) { detail::_interpreter::get(); const size_t dpi = 100; - PyObject* size = PyTuple_New(2); + PyObject* size = PyTuple_New(2); PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); @@ -1933,62 +1999,60 @@ inline void figure_size(size_t w, size_t h) 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); + detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to figure_size() failed."); + if (!res) throw std::runtime_error("Call to figure_size() failed."); Py_DECREF(res); } -inline void legend() -{ +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); } -inline void legend(const std::map& keywords) -{ - detail::_interpreter::get(); +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())); - } + // 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."); + 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); + Py_DECREF(kwargs); + Py_DECREF(res); } -template -inline void set_aspect(Numeric ratio) -{ +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); + 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"); + 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); + PyObject* res = PyObject_Call(set_aspect, args, kwargs); if (!res) throw std::runtime_error("Call to set_aspect() failed."); Py_DECREF(set_aspect); @@ -1997,8 +2061,7 @@ inline void set_aspect(Numeric ratio) Py_DECREF(kwargs); } -inline void set_aspect_equal() -{ +inline void set_aspect_equal() { // expect ratio == "equal". Leaving error handling to matplotlib. detail::_interpreter::get(); @@ -2006,17 +2069,16 @@ inline void set_aspect_equal() 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); + 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"); + 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); + PyObject* res = PyObject_Call(set_aspect, args, kwargs); if (!res) throw std::runtime_error("Call to set_aspect() failed."); Py_DECREF(set_aspect); @@ -2025,9 +2087,8 @@ inline void set_aspect_equal() Py_DECREF(kwargs); } -template -void ylim(Numeric left, Numeric right) -{ +template +void ylim(Numeric left, Numeric right) { detail::_interpreter::get(); PyObject* list = PyList_New(2); @@ -2038,15 +2099,14 @@ void ylim(Numeric left, Numeric right) 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."); + if (!res) throw std::runtime_error("Call to ylim() failed."); Py_DECREF(args); Py_DECREF(res); } -template -void xlim(Numeric left, Numeric right) -{ +template +void xlim(Numeric left, Numeric right) { detail::_interpreter::get(); PyObject* list = PyList_New(2); @@ -2057,45 +2117,41 @@ void xlim(Numeric left, Numeric right) 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."); + if (!res) throw std::runtime_error("Call to xlim() failed."); Py_DECREF(args); Py_DECREF(res); } - -inline std::array xlim() -{ +inline std::array xlim() { PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); + 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); - 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() -{ +inline std::array ylim() { PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); + 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); - 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 = {}) -{ +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(); @@ -2104,7 +2160,7 @@ inline void xticks(const std::vector &ticks, const std::vector &ticks, const std::vector::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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"); + 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) -{ +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 = {}) -{ +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(); @@ -2153,7 +2210,7 @@ inline void yticks(const std::vector &ticks, const std::vector &ticks, const std::vector::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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); + 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"); + 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) -{ +template +inline void yticks(const std::vector& ticks, + const std::map& keywords) { yticks(ticks, {}, keywords); } -template inline void margins(Numeric 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_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) -{ +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_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())); + } -inline void tick_params(const std::map& keywords, const std::string axis = "both") -{ - detail::_interpreter::get(); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); - // construct positional args - PyObject* args; - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str())); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) throw std::runtime_error("Call to tick_params() failed"); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } + Py_DECREF(res); +} +inline void subplot(long nrows, long ncols, long plot_number) { + detail::_interpreter::get(); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyInt_FromLong(nrows)); + PyTuple_SetItem(args, 1, PyInt_FromLong(ncols)); + PyTuple_SetItem(args, 2, PyInt_FromLong(plot_number)); - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) throw std::runtime_error("Call to tick_params() 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(res); + Py_DECREF(args); + Py_DECREF(res); } -inline void subplot(long nrows, long ncols, long plot_number) -{ +inline void subplot(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* args = PyTuple_New(1); + // PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); + // PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); + PyTuple_SetItem(args, 0, PyInt_FromLong(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); } -inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -{ +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); @@ -2284,8 +2356,9 @@ inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, lon 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); @@ -2293,12 +2366,12 @@ inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, lon Py_DECREF(res); } -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ +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); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pytitlestr); PyObject* kwargs = PyDict_New(); @@ -2306,20 +2379,21 @@ inline void title(const std::string &titlestr, const std::mapfirst.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); } -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ +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); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pysuptitlestr); PyObject* kwargs = PyDict_New(); @@ -2327,31 +2401,32 @@ inline void suptitle(const std::string &suptitlestr, const std::mapfirst.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); } -inline void axis(const std::string &axisstr) -{ +inline void axis(const std::string& axisstr) { detail::_interpreter::get(); - PyObject* str = PyString_FromString(axisstr.c_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."); + 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()) -{ +inline void axhline( + double y, double xmin = 0., double xmax = 1., + const std::map& keywords = std::map()) { detail::_interpreter::get(); // construct positional args @@ -2362,21 +2437,23 @@ inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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); - 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()) -{ +inline void axvline( + double x, double ymin = 0., double ymax = 1., + const std::map& keywords = std::map()) { detail::_interpreter::get(); // construct positional args @@ -2387,21 +2464,23 @@ inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map // construct keyword args PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { + 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); + 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()) -{ +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)); @@ -2412,28 +2491,29 @@ inline void axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1. // 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())); - } + 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); + 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 = {}) -{ +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); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); PyObject* kwargs = PyDict_New(); @@ -2441,20 +2521,21 @@ inline void xlabel(const std::string &str, const std::mapfirst.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); } -inline void ylabel(const std::string &str, const std::map& keywords = {}) -{ +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); + PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); PyObject* kwargs = PyDict_New(); @@ -2462,16 +2543,17 @@ inline void ylabel(const std::string &str, const std::mapfirst.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); } -inline void set_zlabel(const std::string &str, const std::map& keywords = {}) -{ +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 @@ -2481,20 +2563,26 @@ inline void set_zlabel(const std::string &str, const std::mapfirst.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); + 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"); + 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); + PyObject* res = PyObject_Call(zlabel, args, kwargs); if (!res) throw std::runtime_error("Call to set_zlabel() failed."); Py_DECREF(zlabel); @@ -2522,8 +2609,7 @@ inline void set_zlabel(const std::string &str, const std::map -inline void pause(Numeric interval) -{ +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."); + 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(); - +inline void savefig(const std::string& filename, + const std::map& keywords = {}) { 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)); + 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_save, args, kwargs); - if (!res) throw std::runtime_error("Call to save() failed."); + if (!res) throw std::runtime_error("Call to savefig() failed."); - Py_DECREF(args); Py_DECREF(kwargs); + Py_DECREF(args); Py_DECREF(res); } +inline void save(const std::string& filename) { + std::cerr << "matplotlibcpp::save is deprecated, use savefig instead\n"; + matplotlibcpp::savefig(filename); +} + inline void rcparams(const std::map& keywords = {}) { detail::_interpreter::get(); - PyObject* args = PyTuple_New(0); + 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())); + 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."); + + 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); @@ -2668,9 +2748,8 @@ inline void rcparams(const std::map& keywords = {}) { inline void clf() { 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."); @@ -2683,8 +2762,7 @@ inline void cla() { 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); } @@ -2692,31 +2770,30 @@ inline void cla() { inline void ion() { 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."); Py_DECREF(res); } -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ +inline std::vector> ginput( + const int numClicks = 1, const std::map& keywords = {}) { detail::_interpreter::get(); - PyObject *args = PyTuple_New(1); + 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) - { + 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); @@ -2726,7 +2803,7 @@ inline std::vector> ginput(const int numClicks = 1, const std::vector> out; out.reserve(len); for (size_t i = 0; i < len; i++) { - PyObject *current = PyList_GetItem(res, 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)); @@ -2741,9 +2818,8 @@ inline std::vector> ginput(const int numClicks = 1, const 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); + 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."); @@ -2754,71 +2830,70 @@ inline void tight_layout() { namespace detail { -template +template using is_function = typename std::is_function>>::type; -template +template struct is_callable_impl; -template -struct is_callable_impl -{ +template +struct is_callable_impl { typedef is_function type; -}; // a non-object is callable iff it is a function +}; // 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: + 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() +}; // an object is callable iff it defines operator() -template -struct is_callable -{ +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) - { +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::distance; using std::end; auto xs = distance(begin(x), end(x)); auto ys = distance(begin(y), end(y)); assert(xs == ys && "x and y data must have the same number of elements!"); - PyObject* xlist = PyList_New(xs); - PyObject* ylist = PyList_New(ys); + PyObject* 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) { + for (size_t i = 0; i < xs; ++i) { PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); } @@ -2828,75 +2903,77 @@ struct plot_impl 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); + 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; +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); + for (auto x : ticks) y.push_back(f(x)); + return plot_impl()(ticks, y, format); } }; -} // end namespace detail +} // 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} ) */ -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); + 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 */ -class Plot -{ -public: +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 = "") { + 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())); + if (name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); PyObject* xarray = detail::get_array(x); PyObject* yarray = detail::get_array(y); @@ -2908,17 +2985,17 @@ class Plot 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) - { - line= PyList_GetItem(res, 0); + if (res) { + line = PyList_GetItem(res, 0); - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); + if (line) + set_data_fct = PyObject_GetAttrString(line, "set_data"); else Py_DECREF(line); Py_DECREF(res); @@ -2930,11 +3007,10 @@ class Plot Plot(const std::string& name = "", const std::string& format = "") : Plot(name, std::vector(), std::vector(), format) {} - template + template bool update(const std::vector& x, const std::vector& y) { assert(x.size() == y.size()); - if(set_data_fct) - { + if (set_data_fct) { PyObject* xarray = detail::get_array(x); PyObject* yarray = detail::get_array(y); @@ -2950,37 +3026,29 @@ class Plot } // clears the plot but keep it available - bool clear() { - return update(std::vector(), std::vector()); - } + 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 (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: + ~Plot() { decref(); } + private: void decref() { - if(line) - Py_DECREF(line); - if(set_data_fct) - Py_DECREF(set_data_fct); + if (line) Py_DECREF(line); + if (set_data_fct) Py_DECREF(set_data_fct); } - - PyObject* line = nullptr; + PyObject* line = nullptr; PyObject* set_data_fct = nullptr; }; -} // end namespace matplotlibcpp +} // end namespace matplotlibcpp