diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..adc0b5cd --- /dev/null +++ b/.clang-format @@ -0,0 +1,17 @@ +--- +BasedOnStyle: Chromium +AccessModifierOffset: '-4' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'true' +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +BreakBeforeBraces: Allman +Cpp11BracedListStyle: 'true' +ColumnLimit: 100 +IndentWidth: '4' +SortIncludes: 'true' +SortUsingDeclarations: 'true' +Standard: Cpp11 + +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..07320903 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,3 @@ +--- +Checks: '-*, cppcoreguidelines-*, clang-analyzer-*, google-*, modernize-*, performance-*, portability-*, readability-*' +WarningsAsErrors: '*' diff --git a/.cmake-format.py b/.cmake-format.py new file mode 100644 index 00000000..dfdc8f15 --- /dev/null +++ b/.cmake-format.py @@ -0,0 +1,36 @@ +# How wide to allow formatted cmake files +line_width = 120 + +# How many spaces to tab for indent +tab_size = 4 + +# If arglists are longer than this, break them always +max_subargs_per_line = 3 + +# If true, separate flow control names from their parentheses with a space +separate_ctrl_name_with_space = False + +# If true, separate function names from parentheses with a space +separate_fn_name_with_space = False + +# If a statement is wrapped to more than one line, than dangle the closing +# parenthesis on it's own line +dangle_parens = False + +# What character to use for bulleted lists +bullet_char = '-' + +# What character to use as punctuation after numerals in an enumerated list +enum_char = '.' + +# What style line endings to use in the output. +line_ending = 'unix' + +# Format command names consistently as 'lower' or 'upper' case +command_case = 'lower' + +# Format keywords consistently as 'lower' or 'upper' case +keyword_case = 'upper' + +# enable comment markup parsing and reflow +enable_markup = False \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7622be79..378eac25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# Logfiles -*.tlog -*.log - -# Build -/examples/build/* +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..ba55edb9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.14) +project(matplotlibcpp-cmake) +# Let CMake paths to easily find our custom CMake modules +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +include(cmake/macros.cmake) + +default_build_type("Release") +common_output_dirs() + +add_subdirectory(src) diff --git a/Makefile b/Makefile deleted file mode 100644 index f9e53668..00000000 --- a/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -examples: minimal basic modern animation nonblock xkcd quiver bar surface fill_inbetween fill update imshow - -minimal: examples/minimal.cpp matplotlibcpp.h - cd examples && g++ -DWITHOUT_NUMPY minimal.cpp -I/usr/include/python2.7 -lpython2.7 -o minimal -std=c++11 - -basic: examples/basic.cpp matplotlibcpp.h - cd examples && g++ basic.cpp -I/usr/include/python2.7 -lpython2.7 -o basic -std=c++11 - -modern: examples/modern.cpp matplotlibcpp.h - cd examples && g++ modern.cpp -I/usr/include/python2.7 -lpython2.7 -o modern -std=c++11 - -animation: examples/animation.cpp matplotlibcpp.h - cd examples && g++ animation.cpp -I/usr/include/python2.7 -lpython2.7 -o animation -std=c++11 - -nonblock: examples/nonblock.cpp matplotlibcpp.h - cd examples && g++ nonblock.cpp -I/usr/include/python2.7 -lpython2.7 -o nonblock -std=c++11 - -quiver: examples/quiver.cpp matplotlibcpp.h - cd examples && g++ quiver.cpp -I/usr/include/python2.7 -lpython2.7 -o quiver -std=c++11 - -xkcd: examples/xkcd.cpp matplotlibcpp.h - cd examples && g++ xkcd.cpp -I/usr/include/python2.7 -lpython2.7 -o xkcd -std=c++11 - -bar: examples/bar.cpp matplotlibcpp.h - cd examples && g++ bar.cpp -I/usr/include/python2.7 -lpython2.7 -o bar -std=c++11 - -surface: examples/surface.cpp matplotlibcpp.h - cd examples && g++ surface.cpp -I/usr/include/python2.7 -lpython2.7 -o surface -std=c++11 - -fill_inbetween: examples/fill_inbetween.cpp matplotlibcpp.h - cd examples && g++ fill_inbetween.cpp -I/usr/include/python2.7 -lpython2.7 -o fill_inbetween -std=c++11 - -fill: examples/fill.cpp matplotlibcpp.h - cd examples && g++ fill.cpp -I/usr/include/python2.7 -lpython2.7 -o fill -std=c++11 - -update: examples/update.cpp matplotlibcpp.h - cd examples && g++ update.cpp -I/usr/include/python2.7 -lpython2.7 -o update -std=c++11 - -imshow: examples/imshow.cpp matplotlibcpp.h - cd examples && g++ imshow.cpp -I/usr/include/python2.7 -lpython2.7 -o imshow -std=c++11 - -clean: - rm -f examples/{minimal,basic,modern,animation,nonblock,xkcd,quiver,bar,surface,fill_inbetween,fill,update,imshow} diff --git a/README.md b/README.md index 338bea7b..d6818591 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ matplotlib-cpp ============== +Forked from lava/matplotlib-cpp. +Wrapped in a proper CMake project for easy usage. + +To compile this project: +`mkdir build && cd build` +`cmake ..` +`make` + +See below for functionality details (copied from source repo): +___ + Welcome to matplotlib-cpp, possibly the simplest C++ plotting library. It is built to resemble the plotting API used by Matlab and matplotlib. @@ -21,7 +32,7 @@ int main() { **Result:** -![Minimal example](./examples/minimal.png) +![Minimal example](./resources/minimal.png) A more comprehensive example: ```cpp @@ -63,7 +74,7 @@ int main() **Result:** -![Basic example](./examples/basic.png) +![Basic example](./resources/basic.png) Alternatively, matplotlib-cpp also supports some C++11-powered syntactic sugar: ```cpp @@ -98,7 +109,7 @@ int main() **Result:** -![Modern example](./examples/modern.png) +![Modern example](./resources/modern.png) Or some *funny-looking xkcd-styled* example: ```cpp @@ -128,7 +139,7 @@ int main() { **Result:** -![xkcd example](./examples/xkcd.png) +![xkcd example](./resources/xkcd.png) When working with vector fields, you might be interested in quiver plots: ```cpp @@ -157,7 +168,7 @@ int main() **Result:** -![quiver example](./examples/quiver.png) +![quiver example](./resources/quiver.png) When working with 3d functions, you might be interested in 3d plots: ```cpp @@ -187,7 +198,7 @@ int main() **Result:** -![surface example](./examples/surface.png) +![surface example](./resources/surface.png) Installation ------------ diff --git a/cmake/macros.cmake b/cmake/macros.cmake new file mode 100644 index 00000000..2baf4957 --- /dev/null +++ b/cmake/macros.cmake @@ -0,0 +1,97 @@ +macro(build_optional var subdir) + message(STATUS "${var}: ${${var}}") + if(${${var}}) + add_subdirectory(${subdir}) + endif() +endmacro() + +macro(common_output_dirs) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/lib) +endmacro() + +# https://blog.kitware.com/cmake-and-the-default-build-type/ +macro(default_build_type) + # Set a default build type if none was specified + if("${ARGV0}" STREQUAL "") + set(build_type "Release") + if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(build_type "Debug") + endif() + else() + set(build_type "${ARGV0}") + endif() + + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${build_type}" CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo") + endif() +endmacro() + +# Enable testing for the project and define helper macros +enable_testing() + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --OUTPUT-ON-FAILURE) + +macro(project_add_test ...) + add_executable(${ARGV}) + set(_testName ${ARGV0}) + + set_target_properties(${_testName} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/test" + LIBRARY_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/test" + ARCHIVE_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/test" + RUNTIME_OUTPUT_DIRECTORY_DEBUG + "${CMAKE_BINARY_DIR}/test" + LIBRARY_OUTPUT_DIRECTORY_DEBUG + "${CMAKE_BINARY_DIR}/test" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG + "${CMAKE_BINARY_DIR}/test" + RUNTIME_OUTPUT_DIRECTORY_RELEASE + "${CMAKE_BINARY_DIR}/test" + LIBRARY_OUTPUT_DIRECTORY_RELEASE + "${CMAKE_BINARY_DIR}/test" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE + "${CMAKE_BINARY_DIR}/test") + + # Integrate the test with ctest for running easily later. + add_test(${_testName} + ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMAKE_SOURCE_DIR}" + "${CMAKE_BINARY_DIR}/test" + --build-target + ${_testName} + --build-generator + ${CMAKE_GENERATOR} + --build-makeprogram + ${CMAKE_MAKE_PROGRAM} + --build-nocmake + --build-noclean + --build-exe-dir + "${CMAKE_BINARY_DIR}/test" + --test-command + ${_testName} + --output-on-failure) + + if(${CODE_COVERAGE}) + add_dependencies(coverage ${_testName}) + endif() +endmacro() diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt deleted file mode 100644 index edb40b11..00000000 --- a/contrib/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.7) -project (MatplotlibCPP_Test) - -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -include_directories(${PYTHONHOME}/include) -include_directories(${PYTHONHOME}/Lib/site-packages/numpy/core/include) -link_directories(${PYTHONHOME}/libs) - -add_definitions(-DMATPLOTLIBCPP_PYTHON_HEADER=Python.h) - -# message(STATUS "*** dump start cmake variables ***") -# get_cmake_property(_variableNames VARIABLES) -# foreach(_variableName ${_variableNames}) -# message(STATUS "${_variableName}=${${_variableName}}") -# endforeach() -# message(STATUS "*** dump end ***") - -add_executable(minimal ${CMAKE_CURRENT_SOURCE_DIR}/../examples/minimal.cpp) -add_executable(basic ${CMAKE_CURRENT_SOURCE_DIR}/../examples/basic.cpp) -add_executable(modern ${CMAKE_CURRENT_SOURCE_DIR}/../examples/modern.cpp) -add_executable(animation ${CMAKE_CURRENT_SOURCE_DIR}/../examples/animation.cpp) -add_executable(nonblock ${CMAKE_CURRENT_SOURCE_DIR}/../examples/nonblock.cpp) -add_executable(xkcd ${CMAKE_CURRENT_SOURCE_DIR}/../examples/xkcd.cpp) -add_executable(bar ${CMAKE_CURRENT_SOURCE_DIR}/../examples/bar.cpp) diff --git a/contrib/README.md b/contrib/README.md deleted file mode 100644 index 0af8515c..00000000 --- a/contrib/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# contrib/ - -This folder contains contributions that may be useful to users of this library, but -have a too specialized audience to become part of the main tree. - -In particular, things in here will have a higher rate of bit-rot, since -contributors are not required to and may be unable to check whether their -changes break any of them. - -## Windows support -Tested on the following environment -* Windows 10 - 64bit -* Anaconda 4.3 (64 bit) -* Python 3.6.0 -* CMake 3.9.4 -* Visual Studio 2017, 2015, 2013 - -### Configuring and Building Samples -1. Edit WinBuild.cmd for your environment(Line:5-7) - if NOT DEFINED MSVC_VERSION set MSVC_VERSION=[Your Visual Studio Version(12, 14, 15)] - if NOT DEFINED CMAKE_CONFIG set CMAKE_CONFIG=Release - if NOT DEFINED PYTHONHOME set PYTHONHOME=[Your Python Path] - -2. Run WinBuild.cmd to build -```cmd -> cd contrib -> WinBuild.cmd -``` -The `WinBuild.cmd` will set up temporal ENV variables and build binaries in (matplotlib root)/examples with the Release configuration. - -3. Find exe files in examples/build/Release -Note: platforms folder is necessary to make qt works. diff --git a/contrib/WinBuild.cmd b/contrib/WinBuild.cmd deleted file mode 100644 index 9dfd627d..00000000 --- a/contrib/WinBuild.cmd +++ /dev/null @@ -1,61 +0,0 @@ -@echo off -@setlocal EnableDelayedExpansion - -REM ------Set Your Environment------------------------------- -if NOT DEFINED MSVC_VERSION set MSVC_VERSION=15 -if NOT DEFINED CMAKE_CONFIG set CMAKE_CONFIG=Release -if NOT DEFINED PYTHONHOME set PYTHONHOME=C:/Users/%username%/Anaconda3 -REM --------------------------------------------------------- - -set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7" -set VALUE_NAME=15.0 - -if "%MSVC_VERSION%"=="14" ( - if "%processor_architecture%" == "AMD64" ( - set CMAKE_GENERATOR=Visual Studio 14 2015 Win64 - ) else ( - set CMAKE_GENERATOR=Visual Studio 14 2015 - ) -) else if "%MSVC_VERSION%"=="12" ( - if "%processor_architecture%" == "AMD64" ( - set CMAKE_GENERATOR=Visual Studio 12 2013 Win64 - ) else ( - set CMAKE_GENERATOR=Visual Studio 12 2013 - ) -) else if "%MSVC_VERSION%"=="15" ( - if "%processor_architecture%" == "AMD64" ( - set CMAKE_GENERATOR=Visual Studio 15 2017 Win64 - ) else ( - set CMAKE_GENERATOR=Visual Studio 15 2017 - ) -) -if "%MSVC_VERSION%"=="15" ( - for /F "usebackq tokens=1,2,*" %%A in (`REG QUERY %KEY_NAME% /v %VALUE_NAME%`) do ( - set batch_file=%%CVC\Auxiliary\Build\vcvarsall.bat - ) -) else ( - set batch_file=!VS%MSVC_VERSION%0COMNTOOLS!..\..\VC\vcvarsall.bat -) -call "%batch_file%" %processor_architecture% - -pushd .. -pushd examples -if NOT EXIST build mkdir build -pushd build - -cmake -G"!CMAKE_GENERATOR!" ^ - -DPYTHONHOME:STRING=%PYTHONHOME%^ - -DCMAKE_BUILD_TYPE:STRING=%CMAKE_CONFIG% ^ - %~dp0 -cmake --build . --config %CMAKE_CONFIG% - -pushd %CMAKE_CONFIG% -if not EXIST platforms mkdir platforms -if EXIST %PYTHONHOME%/Library/plugins/platforms/qwindows.dll ^ -cp %PYTHONHOME%/Library/plugins/platforms/qwindows.dll ./platforms/ -popd -REM move ./%CMAKE_CONFIG% ../ -popd -popd -popd -@endlocal diff --git a/examples/animation.cpp b/examples/animation.cpp deleted file mode 100644 index d9794300..00000000 --- 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 - -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/minimal.cpp b/examples/minimal.cpp deleted file mode 100644 index fbe1e1cd..00000000 --- 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/modern.cpp b/examples/modern.cpp deleted file mode 100644 index a8aa0c75..00000000 --- a/examples/modern.cpp +++ /dev/null @@ -1,30 +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 /dev/null; then + echo \"Please install clang-format.\" + exit 1 +fi + +find ./src -iname *.h -o -iname *.hpp -o -iname *.cpp -o -iname *.c -o -iname *.cc -o -iname *.tpp \ + | xargs clang-format-6.0 -style=file -i -fallback-style=none + +# Check if cmake-format is installed. +if ! type cmake-format > /dev/null; then + echo \"Please install cmake-format.\" + exit 1 +fi + + +# Run cmake-format an all CMakeLists.txt and *.cmake files +ROOT=$(git rev-parse --show-toplevel) +find $ROOT -iname CMakeLists.txt -o -iname *.cmake \ + | xargs cmake-format -i \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..2a9ec7e5 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(lib) +add_subdirectory(examples) diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt new file mode 100644 index 00000000..6b980148 --- /dev/null +++ b/src/examples/CMakeLists.txt @@ -0,0 +1,20 @@ +add_executable(minimal minimal.cpp) +target_link_libraries(minimal matplotlibcpp) + +add_executable(basic basic.cpp) +target_link_libraries(basic matplotlibcpp) + +add_executable(modern modern.cpp) +target_link_libraries(modern matplotlibcpp) + +add_executable(animation animation.cpp) +target_link_libraries(animation matplotlibcpp) + +add_executable(nonblock nonblock.cpp) +target_link_libraries(nonblock matplotlibcpp) + +add_executable(xkcd xkcd.cpp) +target_link_libraries(xkcd matplotlibcpp) + +add_executable(bar bar.cpp) +target_link_libraries(bar matplotlibcpp) diff --git a/src/examples/animation.cpp b/src/examples/animation.cpp new file mode 100644 index 00000000..13d3cc05 --- /dev/null +++ b/src/examples/animation.cpp @@ -0,0 +1,38 @@ +#define _USE_MATH_DEFINES +#include +#include + +namespace plt = matplotlibcpp; + +int main() +{ + int n = 1000; + std::vector x, y, z; + + for (int i = 0; i < n; i++) + { + x.push_back(i * i); + y.push_back(sin(2 * M_PI * i / 360.0)); + z.push_back(log(i)); + + if (i % 10 == 0) + { + // Clear previous plot + plt::clf(); + // Plot line from given x and y data. Color is selected automatically. + plt::plot(x, y); + // Plot a line whose name will show up as "log(x)" in the legend. + plt::named_plot("log(x)", x, z); + + // Set x-axis to interval [0,1000000] + plt::xlim(0, n * n); + + // Add graph title + plt::title("Sample figure"); + // Enable legend. + plt::legend(); + // Display plot continuously + plt::pause(0.01); + } + } +} diff --git a/examples/bar.cpp b/src/examples/bar.cpp similarity index 66% rename from examples/bar.cpp rename to src/examples/bar.cpp index 86423adf..ef5b4ac2 100644 --- a/examples/bar.cpp +++ b/src/examples/bar.cpp @@ -1,13 +1,15 @@ #define _USE_MATH_DEFINES +#include #include #include -#include "../matplotlibcpp.h" namespace plt = matplotlibcpp; -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ std::vector test_data; - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 20; i++) + { test_data.push_back(i); } diff --git a/examples/basic.cpp b/src/examples/basic.cpp similarity index 68% rename from examples/basic.cpp rename to src/examples/basic.cpp index 2dc34c74..989145eb 100644 --- a/examples/basic.cpp +++ b/src/examples/basic.cpp @@ -1,21 +1,22 @@ #define _USE_MATH_DEFINES -#include +#include #include -#include "../matplotlibcpp.h" +#include namespace plt = matplotlibcpp; -int main() +int main() { // Prepare data. int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i 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); } - + // Set the size of output image = 1200x780 pixels plt::figure_size(1200, 780); @@ -23,13 +24,13 @@ int main() plt::plot(x, y); // Plot a red dashed line from given x and y data. - plt::plot(x, w,"r--"); + plt::plot(x, w, "r--"); // Plot a line whose name will show up as "log(x)" in the legend. plt::named_plot("log(x)", x, z); // Set x-axis to interval [0,1000000] - plt::xlim(0, 1000*1000); + plt::xlim(0, 1000 * 1000); // Add graph title plt::title("Sample figure"); @@ -39,6 +40,7 @@ int main() // save figure const char* filename = "./basic.png"; - std::cout << "Saving result to " << filename << std::endl;; + std::cout << "Saving result to " << filename << std::endl; + ; plt::save(filename); } diff --git a/examples/fill.cpp b/src/examples/fill.cpp similarity index 57% rename from examples/fill.cpp rename to src/examples/fill.cpp index 6059b475..bd533d4a 100644 --- a/examples/fill.cpp +++ b/src/examples/fill.cpp @@ -1,5 +1,5 @@ #define _USE_MATH_DEFINES -#include "../matplotlibcpp.h" +#include #include using namespace std; @@ -7,7 +7,8 @@ namespace plt = matplotlibcpp; // Example fill plot taken from: // https://matplotlib.org/gallery/misc/fill_spiral.html -int main() { +int main() +{ // Prepare data. vector theta; for (double d = 0; d < 8 * M_PI; d += 0.1) @@ -16,14 +17,16 @@ int main() { const int a = 1; const double b = 0.2; - for (double dt = 0; dt < 2 * M_PI; dt += M_PI/2.0) { + 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) ); + 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) ); + 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()); diff --git a/src/examples/fill_inbetween.cpp b/src/examples/fill_inbetween.cpp new file mode 100644 index 00000000..0ba259ba --- /dev/null +++ b/src/examples/fill_inbetween.cpp @@ -0,0 +1,30 @@ +#define _USE_MATH_DEFINES +#include +#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/src/examples/imshow.cpp similarity index 68% rename from examples/imshow.cpp rename to src/examples/imshow.cpp index b11661e4..14c7a0ce 100644 --- a/examples/imshow.cpp +++ b/src/examples/imshow.cpp @@ -1,7 +1,7 @@ #define _USE_MATH_DEFINES +#include #include #include -#include "../matplotlibcpp.h" using namespace std; namespace plt = matplotlibcpp; @@ -11,9 +11,11 @@ int main() // Prepare data int ncols = 500, nrows = 300; std::vector z(ncols * nrows); - for (int j=0; j + +namespace plt = matplotlibcpp; + +int main() +{ + plt::plot({1, 3, 2, 4}); + plt::show(); +} diff --git a/src/examples/modern.cpp b/src/examples/modern.cpp new file mode 100644 index 00000000..4fa30400 --- /dev/null +++ b/src/examples/modern.cpp @@ -0,0 +1,30 @@ +#define _USE_MATH_DEFINES +#include +#include + +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 < n; ++i) + { + double t = 2 * M_PI * i / n; + x.at(i) = 16 * sin(t) * sin(t) * sin(t); + y.at(i) = 13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t); + } + + // plot() takes an arbitrary number of (x,y,format)-triples. + // x must be iterable (that is, anything providing begin(x) and end(x)), + // y must either be callable (providing operator() const) or iterable. + plt::plot(x, y, "r-", x, [](double d) { return 12.5 + abs(sin(d)); }, "k-"); + + // show plots + plt::show(); +} diff --git a/examples/nonblock.cpp b/src/examples/nonblock.cpp similarity index 68% rename from examples/nonblock.cpp rename to src/examples/nonblock.cpp index 327d96c7..0f77f24a 100644 --- a/examples/nonblock.cpp +++ b/src/examples/nonblock.cpp @@ -1,10 +1,9 @@ #define _USE_MATH_DEFINES +#include #include -#include "../matplotlibcpp.h" namespace plt = matplotlibcpp; - using namespace matplotlibcpp; using namespace std; @@ -12,27 +11,28 @@ int main() { // Prepare data. int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i x(n), y(n), z(n), w(n, 2); + for (int i = 0; i < n; ++i) + { + x.at(i) = i * i; + y.at(i) = sin(2 * M_PI * i / 360.0); z.at(i) = log(i); } // Plot line from given x and y data. Color is selected automatically. - plt::subplot(2,2,1); + plt::subplot(2, 2, 1); plt::plot(x, y); // Plot a red dashed line from given x and y data. - plt::subplot(2,2,2); - plt::plot(x, w,"r--"); + plt::subplot(2, 2, 2); + plt::plot(x, w, "r--"); // Plot a line whose name will show up as "log(x)" in the legend. - plt::subplot(2,2,3); + plt::subplot(2, 2, 3); plt::named_plot("log(x)", x, z); // Set x-axis to interval [0,1000000] - plt::xlim(0, 1000*1000); + plt::xlim(0, 1000 * 1000); // Add graph title plt::title("Sample figure"); diff --git a/examples/quiver.cpp b/src/examples/quiver.cpp similarity index 72% rename from examples/quiver.cpp rename to src/examples/quiver.cpp index ea3c3eca..7a7b24cb 100644 --- a/examples/quiver.cpp +++ b/src/examples/quiver.cpp @@ -1,4 +1,4 @@ -#include "../matplotlibcpp.h" +#include namespace plt = matplotlibcpp; @@ -6,8 +6,10 @@ int main() { // u and v are respectively the x and y components of the arrows we're plotting std::vector x, y, u, v; - for (int i = -5; i <= 5; i++) { - for (int j = -5; j <= 5; j++) { + 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); diff --git a/examples/subplot.cpp b/src/examples/subplot.cpp similarity index 50% rename from examples/subplot.cpp rename to src/examples/subplot.cpp index bee322e0..f5ead200 100644 --- a/examples/subplot.cpp +++ b/src/examples/subplot.cpp @@ -1,31 +1,31 @@ #define _USE_MATH_DEFINES +#include #include -#include "../matplotlibcpp.h" using namespace std; namespace plt = matplotlibcpp; -int main() +int main() { // Prepare data - int n = 500; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i x(n), y(n), z(n), w(n, 2); + for (int i = 0; i < n; ++i) + { + x.at(i) = i; + y.at(i) = sin(2 * M_PI * i / 360.0); + z.at(i) = 100.0 / i; + } // Set the "super title" plt::suptitle("My plot"); plt::subplot(1, 2, 1); - plt::plot(x, y, "r-"); + plt::plot(x, y, "r-"); plt::subplot(1, 2, 2); plt::plot(x, z, "k-"); // Add some text to the plot plt::text(100, 90, "Hello!"); - - // Show plots - plt::show(); + // Show plots + plt::show(); } diff --git a/examples/surface.cpp b/src/examples/surface.cpp similarity index 74% rename from examples/surface.cpp rename to src/examples/surface.cpp index 4865f061..193dc432 100644 --- a/examples/surface.cpp +++ b/src/examples/surface.cpp @@ -1,4 +1,4 @@ -#include "../matplotlibcpp.h" +#include #include @@ -7,9 +7,11 @@ namespace plt = matplotlibcpp; int main() { std::vector> x, y, z; - for (double i = -5; i <= 5; i += 0.25) { + 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) { + 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))); diff --git a/examples/update.cpp b/src/examples/update.cpp similarity index 57% rename from examples/update.cpp rename to src/examples/update.cpp index 64f49067..93f40bfd 100644 --- a/examples/update.cpp +++ b/src/examples/update.cpp @@ -1,34 +1,37 @@ #define _USE_MATH_DEFINES -#include -#include "../matplotlibcpp.h" +#include #include +#include namespace plt = matplotlibcpp; -void update_window(const double x, const double y, const double t, - std::vector &xt, std::vector &yt) +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))); + 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; + 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; + const double a = n / 2; - for (size_t i=0; i xt(2), yt(2); @@ -46,9 +49,11 @@ int main() plt::legend(); - for (size_t i=0; i #include -#include "../matplotlibcpp.h" #include namespace plt = matplotlibcpp; -int main() { +int main() +{ std::vector t(1000); std::vector x(t.size()); - for(size_t i = 0; i < t.size(); i++) { + 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]); } @@ -19,4 +21,3 @@ int main() { plt::title("AN ORDINARY SIN WAVE"); plt::show(); } - diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt new file mode 100644 index 00000000..27688f1f --- /dev/null +++ b/src/lib/CMakeLists.txt @@ -0,0 +1,7 @@ +find_package(Python COMPONENTS NumPy) +include_directories(.) + +add_library(matplotlibcpp INTERFACE) +target_include_directories(matplotlibcpp INTERFACE . ${Python_INCLUDE_DIRS} ${Python_NumPy_INCLUDE_DIRS}) +target_link_libraries(matplotlibcpp INTERFACE ${Python_LIBRARIES}) +# target_link_libraries(matplotlibcpp INTERFACE ${Python_LIBRARIES}) diff --git a/matplotlibcpp.h b/src/lib/matplotlibcpp/matplotlibcpp.h similarity index 52% rename from matplotlibcpp.h rename to src/lib/matplotlibcpp/matplotlibcpp.h index e626c4cf..9da8bfd7 100644 --- a/matplotlibcpp.h +++ b/src/lib/matplotlibcpp/matplotlibcpp.h @@ -1,82 +1,82 @@ #pragma once -#include -#include +#include #include +#include // requires c++11 support +#include +#include +#include #include -#include #include -#include -#include // requires c++11 support -#include +#include #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 -#endif // WITHOUT_NUMPY +#ifdef WITH_OPENCV +#include +#endif // WITH_OPENCV +#endif // WITHOUT_NUMPY #if PY_MAJOR_VERSION >= 3 -# define PyString_FromString PyUnicode_FromString -# define PyInt_FromLong PyLong_FromLong -# define PyString_FromString PyUnicode_FromString +#define PyString_FromString PyUnicode_FromString +#define PyInt_FromLong PyLong_FromLong +#define PyString_FromString PyUnicode_FromString #endif - -namespace matplotlibcpp { -namespace detail { - +namespace matplotlibcpp +{ +namespace detail +{ static std::string s_backend; -struct _interpreter { - PyObject *s_python_function_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_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_subplot; - 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_xlabel; - PyObject *s_python_function_ylabel; - PyObject *s_python_function_xticks; - PyObject *s_python_function_yticks; - PyObject *s_python_function_grid; - PyObject *s_python_function_clf; - PyObject *s_python_function_errorbar; - PyObject *s_python_function_annotate; - PyObject *s_python_function_tight_layout; - PyObject *s_python_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_subplots_adjust; - +struct _interpreter +{ + PyObject* s_python_function_show; + PyObject* s_python_function_close; + PyObject* s_python_function_draw; + PyObject* s_python_function_pause; + PyObject* s_python_function_save; + PyObject* s_python_function_figure; + PyObject* s_python_function_fignum_exists; + PyObject* s_python_function_plot; + PyObject* s_python_function_quiver; + 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_subplot; + 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_xlabel; + PyObject* s_python_function_ylabel; + PyObject* s_python_function_xticks; + PyObject* s_python_function_yticks; + PyObject* s_python_function_grid; + PyObject* s_python_function_clf; + PyObject* s_python_function_errorbar; + PyObject* s_python_function_annotate; + PyObject* s_python_function_tight_layout; + PyObject* s_python_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_subplots_adjust; /* 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 @@ -84,12 +84,14 @@ struct _interpreter { http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program */ - static _interpreter& get() { + static _interpreter& get() + { static _interpreter ctx; return ctx; } - PyObject* safe_import(PyObject* module, std::string fname) { + PyObject* safe_import(PyObject* module, std::string fname) + { PyObject* fn = PyObject_GetAttrString(module, fname.c_str()); if (!fn) @@ -102,26 +104,27 @@ struct _interpreter { } 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 + void import_numpy() + { + import_array(); // initialize C-API } -# endif +#endif #endif - _interpreter() { - + _interpreter() + { // optional but recommended #if PY_MAJOR_VERSION >= 3 wchar_t name[] = L"plotting"; @@ -132,41 +135,54 @@ struct _interpreter { Py_Initialize(); #ifndef WITHOUT_NUMPY - import_numpy(); // initialize numpy C-API + import_numpy(); // initialize numpy C-API #endif PyObject* matplotlibname = PyString_FromString("matplotlib"); PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); - PyObject* cmname = PyString_FromString("matplotlib.cm"); - PyObject* pylabname = PyString_FromString("pylab"); - if (!pyplotname || !pylabname || !matplotlibname || !cmname) { + PyObject* cmname = PyString_FromString("matplotlib.cm"); + PyObject* pylabname = PyString_FromString("pylab"); + if (!pyplotname || !pylabname || !matplotlibname || !cmname) + { throw std::runtime_error("couldnt create string"); } PyObject* matplotlib = PyImport_Import(matplotlibname); Py_DECREF(matplotlibname); - if (!matplotlib) { + if (!matplotlib) + { PyErr_Print(); throw std::runtime_error("Error loading module matplotlib!"); } // matplotlib.use() must be called *before* pylab, matplotlib.pyplot, // or matplotlib.backends is imported for the first time - if (!s_backend.empty()) { - PyObject_CallMethod(matplotlib, const_cast("use"), const_cast("s"), s_backend.c_str()); + if (!s_backend.empty()) + { + PyObject_CallMethod(matplotlib, const_cast("use"), const_cast("s"), + s_backend.c_str()); } PyObject* pymod = PyImport_Import(pyplotname); Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } + 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!"); } + if (!pylabmod) + { + throw std::runtime_error("Error loading module pylab!"); + } s_python_function_show = safe_import(pymod, "show"); s_python_function_close = safe_import(pymod, "close"); @@ -181,8 +197,8 @@ struct _interpreter { 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_hist = safe_import(pymod, "hist"); + s_python_function_scatter = safe_import(pymod, "scatter"); s_python_function_subplot = safe_import(pymod, "subplot"); s_python_function_legend = safe_import(pymod, "legend"); s_python_function_ylim = safe_import(pymod, "ylim"); @@ -197,7 +213,7 @@ struct _interpreter { 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_annotate = safe_import(pymod, "annotate"); 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"); @@ -205,8 +221,8 @@ struct _interpreter { 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_subplots_adjust = safe_import(pymod,"subplots_adjust"); + s_python_function_bar = safe_import(pymod, "bar"); + s_python_function_subplots_adjust = safe_import(pymod, "subplots_adjust"); #ifndef WITHOUT_NUMPY s_python_function_imshow = safe_import(pymod, "imshow"); #endif @@ -214,12 +230,10 @@ struct _interpreter { s_python_empty_tuple = PyTuple_New(0); } - ~_interpreter() { - Py_Finalize(); - } + ~_interpreter() { Py_Finalize(); } }; -} // end namespace detail +} // end namespace detail // must be called before the first regular call to matplotlib to have any effect inline void backend(const std::string& name) @@ -229,11 +243,11 @@ inline void backend(const std::string& name) inline bool annotate(std::string annotation, double x, double y) { - 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); @@ -241,41 +255,92 @@ 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; } #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 +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 PyObject* get_array(const std::vector& v) { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work + detail::_interpreter::get(); // interpreter needs to be initialized for the numpy commands to + // work NPY_TYPES type = select_npy_type::type; if (type == NPY_NOTYPE) { std::vector vd(v.size()); npy_intp vsize = v.size(); - std::copy(v.begin(),v.end(),vd.begin()); + std::copy(v.begin(), v.end(), vd.begin()); PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data())); return varray; } @@ -285,46 +350,50 @@ PyObject* get_array(const std::vector& v) return varray; } -template +template PyObject* get_2darray(const std::vector<::std::vector>& v) { - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); + detail::_interpreter::get(); // interpreter needs to be initialized for the numpy commands to + // work + 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 +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 -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()); @@ -339,7 +408,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())); } @@ -348,105 +418,122 @@ 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; } 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()) -{ - // 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 = get_2darray(x); - PyObject *yarray = get_2darray(y); - PyObject *zarray = 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); +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()) +{ + // 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(); - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); - PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); + 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 *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); + mpl_toolkitsmod = PyImport_Import(mpl_toolkits); + Py_DECREF(mpl_toolkits); + if (!mpl_toolkitsmod) + { + throw std::runtime_error("Error loading module mpl_toolkits!"); + } - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); + axis3dmod = PyImport_Import(axis3d); + Py_DECREF(axis3d); + if (!axis3dmod) + { + throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); + } + } - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } + assert(x.size() == y.size()); + assert(y.size() == z.size()); + // using numpy arrays + PyObject* xarray = get_2darray(x); + PyObject* yarray = get_2darray(y); + PyObject* zarray = get_2darray(z); - 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."); + // construct positional args + PyObject* args = PyTuple_New(3); + PyTuple_SetItem(args, 0, xarray); + PyTuple_SetItem(args, 1, yarray); + PyTuple_SetItem(args, 2, zarray); - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); + // Build up the kw args. + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); + PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); - 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); + PyObject* python_colormap_coolwarm = + PyObject_GetAttrString(detail::_interpreter::get().s_python_colormap, "coolwarm"); - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); + PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); + 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_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); + 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); + + 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); + 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) +template +bool stem(const std::vector& x, + const std::vector& y, + const std::map& keywords) { assert(x.size() == y.size()); @@ -461,14 +548,13 @@ 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); @@ -478,8 +564,10 @@ bool stem(const std::vector &x, const std::vector &y, const st 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()); @@ -494,7 +582,8 @@ bool fill(const std::vector& x, const std::vector& y, const st // construct keyword args PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } @@ -503,13 +592,17 @@ bool fill(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; } -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()); @@ -527,24 +620,30 @@ 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; } -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) { - PyObject* yarray = get_array(y); PyObject* kwargs = PyDict_New(); @@ -557,93 +656,106 @@ 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; } #ifndef WITHOUT_NUMPY - namespace internal { - void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map &keywords) - { - assert(type == NPY_UINT8 || type == NPY_FLOAT); - assert(colors == 1 || colors == 3 || colors == 4); - - detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work - - // construct args - npy_intp dims[3] = { rows, columns, colors }; - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) - throw std::runtime_error("Call to imshow() failed"); - Py_DECREF(res); - } - } +namespace internal +{ +void imshow(void* ptr, + const NPY_TYPES type, + const int rows, + const int columns, + const int colors, + const std::map& keywords) +{ + assert(type == NPY_UINT8 || type == NPY_FLOAT); + assert(colors == 1 || colors == 3 || colors == 4); - void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}) - { - internal::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords); - } + detail::_interpreter::get(); // interpreter needs to be initialized for the numpy commands to + // work + + // 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)); - void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}) + // construct keyword args + PyObject* kwargs = PyDict_New(); + for (std::map::const_iterator it = keywords.begin(); + it != keywords.end(); ++it) { - internal::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords); + PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs); + Py_DECREF(args); + Py_DECREF(kwargs); + if (!res) + throw std::runtime_error("Call to imshow() failed"); + Py_DECREF(res); +} +} // namespace internal + +void imshow(const unsigned char* ptr, + const int rows, + const int columns, + const int colors, + const std::map& keywords = {}) +{ + internal::imshow((void*)ptr, NPY_UINT8, rows, columns, colors, keywords); +} + +void imshow(const float* ptr, + const int rows, + const int columns, + const int colors, + const std::map& keywords = {}) +{ + internal::imshow((void*)ptr, NPY_FLOAT, rows, columns, colors, keywords); +} + #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) { - // 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_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); - } + default: image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels())); + } - internal::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords); + // 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); } -#endif // WITH_OPENCV -#endif // WITHOUT_NUMPY -template + internal::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords); +} +#endif // WITH_OPENCV +#endif // WITHOUT_NUMPY + +template bool scatter(const std::vector& x, const std::vector& y, - const double s=1.0) // The marker size in points**2 + const double s = 1.0) // The marker size in points**2 { assert(x.size() == y.size()); @@ -657,17 +769,22 @@ 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< typename Numeric> -bool bar(const std::vector& y, std::string ec = "black", std::string ls = "-", double lw = 1.0, +template +bool bar(const std::vector& y, + std::string ec = "black", + std::string ls = "-", + double lw = 1.0, const std::map& keywords = {}) { PyObject* yarray = get_array(y); @@ -688,39 +805,45 @@ bool bar(const std::vector& y, std::string ec = "black", std::string ls PyTuple_SetItem(plot_args, 0, xarray); PyTuple_SetItem(plot_args, 1, yarray); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); Py_DECREF(plot_args); Py_DECREF(kwargs); - if(res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } inline bool subplots_adjust(const std::map& keywords = {}) { - 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) { PyObject* yarray = get_array(y); @@ -730,20 +853,21 @@ 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 +template bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") { assert(x.size() == y.size()); @@ -758,16 +882,22 @@ 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; } -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()); @@ -784,13 +914,14 @@ 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); @@ -800,7 +931,7 @@ bool quiver(const std::vector& x, const std::vector& y, cons return res; } -template +template bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") { assert(x.size() == y.size()); @@ -815,8 +946,8 @@ 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) @@ -825,8 +956,10 @@ bool stem(const std::vector& x, const std::vector& y, const 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()); @@ -840,16 +973,20 @@ 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()); @@ -863,16 +1000,20 @@ 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()); @@ -886,16 +1027,21 @@ 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()); @@ -905,18 +1051,20 @@ bool errorbar(const std::vector &x, const std::vector &y, co // 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); @@ -929,8 +1077,10 @@ 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 = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -944,17 +1094,22 @@ 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); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +template +bool named_plot(const std::string& name, + const std::vector& x, + const std::vector& y, + const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -969,17 +1124,22 @@ bool named_plot(const std::string& name, const std::vector& x, const st PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +template +bool named_semilogx(const std::string& name, + const std::vector& x, + const std::vector& y, + const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -994,17 +1154,22 @@ bool named_semilogx(const std::string& name, const std::vector& x, cons PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +template +bool named_semilogy(const std::string& name, + const std::vector& x, + const std::vector& y, + const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1019,17 +1184,22 @@ bool named_semilogy(const std::string& name, const std::vector& x, cons PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); Py_DECREF(kwargs); Py_DECREF(plot_args); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") +template +bool named_loglog(const std::string& name, + const std::vector& x, + const std::vector& y, + const std::string& format = "") { PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); @@ -1044,40 +1214,45 @@ bool named_loglog(const std::string& name, const std::vector& x, const 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); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } -template +template bool plot(const std::vector& y, const std::string& format = "") { std::vector x(y.size()); - for(size_t i=0; i +template bool plot(const std::vector& y, const std::map& keywords) { std::vector x(y.size()); - for(size_t i=0; i +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; + for (size_t i = 0; i < x.size(); ++i) + x.at(i) = i; return stem(x, y, format); } -template +template void text(Numeric x, Numeric y, const std::string& s = "") { PyObject* args = PyTuple_New(3); @@ -1086,34 +1261,38 @@ void text(Numeric x, Numeric y, const std::string& s = "") 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."); + if (!res) + throw std::runtime_error("Call to text() failed."); Py_DECREF(args); Py_DECREF(res); } - inline long figure(long number = -1) { - PyObject *res; + PyObject* res; if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); - else { + 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"); + if (!num) + throw std::runtime_error("Could not get number attribute of figure object"); const long figureNumber = PyLong_AsLong(num); Py_DECREF(num); @@ -1127,10 +1306,12 @@ inline bool fignum_exists(long number) // 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)); - 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); @@ -1154,23 +1335,26 @@ 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() { - 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); } -template +template void ylim(Numeric left, Numeric right) { PyObject* list = PyList_New(2); @@ -1181,13 +1365,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 +template void xlim(Numeric left, Numeric right) { PyObject* list = PyList_New(2); @@ -1198,50 +1383,53 @@ 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 double* xlim() { PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); + PyObject* left = PyTuple_GetItem(res, 0); + PyObject* right = PyTuple_GetItem(res, 1); double* arr = new double[2]; arr[0] = PyFloat_AsDouble(left); arr[1] = PyFloat_AsDouble(right); - if(!res) throw std::runtime_error("Call to xlim() failed."); + if (!res) + throw std::runtime_error("Call to xlim() failed."); Py_DECREF(res); return arr; } - inline double* ylim() { PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); + PyObject* left = PyTuple_GetItem(res, 0); + PyObject* right = PyTuple_GetItem(res, 1); double* arr = new double[2]; arr[0] = PyFloat_AsDouble(left); arr[1] = PyFloat_AsDouble(right); - if(!res) throw std::runtime_error("Call to ylim() failed."); + if (!res) + throw std::runtime_error("Call to ylim() failed."); Py_DECREF(res); return arr; } -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()); @@ -1249,11 +1437,14 @@ 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()); @@ -1296,11 +1493,14 @@ 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); } @@ -1342,96 +1546,113 @@ inline void subplot(long nrows, long ncols, long plot_number) PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); - if(!res) throw std::runtime_error("Call to subplot() failed."); + PyObject* res = + PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); + if (!res) + throw std::runtime_error("Call to subplot() failed."); Py_DECREF(args); Py_DECREF(res); } -inline void title(const std::string &titlestr, const std::map &keywords = {}) +inline void title(const std::string& titlestr, + const std::map& keywords = {}) { PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pytitlestr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); - if(!res) throw std::runtime_error("Call to title() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); + if (!res) + throw std::runtime_error("Call to title() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) +inline void suptitle(const std::string& suptitlestr, + const std::map& keywords = {}) { PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pysuptitlestr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); - if(!res) throw std::runtime_error("Call to suptitle() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); + if (!res) + throw std::runtime_error("Call to suptitle() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void axis(const std::string &axisstr) +inline void axis(const std::string& axisstr) { PyObject* str = PyString_FromString(axisstr.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, str); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); + if (!res) + throw std::runtime_error("Call to title() failed."); Py_DECREF(args); 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 = {}) { PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to xlabel() failed."); Py_DECREF(args); Py_DECREF(kwargs); Py_DECREF(res); } -inline void ylabel(const std::string &str, const std::map& keywords = {}) +inline void ylabel(const std::string& str, const std::map& keywords = {}) { PyObject* pystr = PyString_FromString(str.c_str()); PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, pystr); PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { + for (auto it = keywords.begin(); it != keywords.end(); ++it) + { PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); - if(!res) throw std::runtime_error("Call to ylabel() failed."); + PyObject* res = + PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); + if (!res) + throw std::runtime_error("Call to ylabel() failed."); Py_DECREF(args); Py_DECREF(kwargs); @@ -1447,7 +1668,8 @@ inline void grid(bool flag) PyTuple_SetItem(args, 0, pyflag); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); + if (!res) + throw std::runtime_error("Call to grid() failed."); Py_DECREF(args); Py_DECREF(res); @@ -1456,43 +1678,44 @@ inline void grid(bool flag) inline void show(const bool block = true) { PyObject* res; - if(block) + if (block) { - res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_show, - detail::_interpreter::get().s_python_empty_tuple); + res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, + detail::_interpreter::get().s_python_empty_tuple); } else { - PyObject *kwargs = PyDict_New(); + PyObject* kwargs = PyDict_New(); PyDict_SetItemString(kwargs, "block", Py_False); - res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs); - Py_DECREF(kwargs); + res = PyObject_Call(detail::_interpreter::get().s_python_function_show, + detail::_interpreter::get().s_python_empty_tuple, kwargs); + Py_DECREF(kwargs); } - - if (!res) throw std::runtime_error("Call to show() failed."); + if (!res) + throw std::runtime_error("Call to show() failed."); Py_DECREF(res); } inline void close() { - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_close, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_close, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to close() failed."); + if (!res) + throw std::runtime_error("Call to close() failed."); Py_DECREF(res); } -inline void xkcd() { +inline void xkcd() +{ PyObject* res; - PyObject *kwargs = PyDict_New(); + PyObject* kwargs = PyDict_New(); res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, - detail::_interpreter::get().s_python_empty_tuple, kwargs); + detail::_interpreter::get().s_python_empty_tuple, kwargs); Py_DECREF(kwargs); @@ -1504,23 +1727,24 @@ inline void xkcd() { inline void draw() { - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_draw, - detail::_interpreter::get().s_python_empty_tuple); + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_draw, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to draw() failed."); + if (!res) + throw std::runtime_error("Call to draw() failed."); Py_DECREF(res); } -template +template inline void pause(Numeric interval) { PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); - if(!res) throw std::runtime_error("Call to pause() failed."); + if (!res) + throw std::runtime_error("Call to pause() failed."); Py_DECREF(args); Py_DECREF(res); @@ -1534,56 +1758,64 @@ inline void save(const std::string& filename) PyTuple_SetItem(args, 0, pyfilename); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args); - if (!res) throw std::runtime_error("Call to save() failed."); + if (!res) + throw std::runtime_error("Call to save() failed."); Py_DECREF(args); Py_DECREF(res); } -inline void clf() { - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); +inline void clf() +{ + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_clf, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to clf() failed."); + if (!res) + throw std::runtime_error("Call to clf() failed."); Py_DECREF(res); } - inline void ion() { - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); +inline void ion() +{ + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ion, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to ion() failed."); + 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 = {}) { - 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); - if (!res) throw std::runtime_error("Call to ginput() failed."); + if (!res) + throw std::runtime_error("Call to ginput() failed."); const size_t len = PyList_Size(res); std::vector> out; out.reserve(len); - for (size_t i = 0; i < len; i++) { - PyObject *current = PyList_GetItem(res, i); + for (size_t i = 0; i < len; i++) + { + PyObject* current = PyList_GetItem(res, i); std::array position; position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0)); position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1)); @@ -1595,71 +1827,82 @@ inline std::vector> ginput(const int numClicks = 1, const } // Actually, is there any reason not to call this automatically for every plot? -inline void tight_layout() { - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_tight_layout, - detail::_interpreter::get().s_python_empty_tuple); +inline void tight_layout() +{ + PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_tight_layout, + detail::_interpreter::get().s_python_empty_tuple); - if (!res) throw std::runtime_error("Call to tight_layout() failed."); + if (!res) + throw std::runtime_error("Call to tight_layout() failed."); Py_DECREF(res); } // Support for variadic plot() and initializer lists: -namespace detail { - -template +namespace detail +{ +template using is_function = typename std::is_function>>::type; -template +template struct is_callable_impl; -template +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 +template struct is_callable_impl { - struct Fallback { void operator()(); }; - struct Derived : T, Fallback { }; + struct Fallback + { + void operator()(); + }; + struct Derived : T, Fallback + { + }; - template struct Check; + template + struct Check; - template - static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match + template + static std::true_type test(...); // use a variadic function to make sure (1) it accepts + // everything and (2) its always the worst match - template - static std::false_type test( Check* ); + template + static std::false_type test(Check*); public: typedef decltype(test(nullptr)) type; typedef decltype(&Fallback::operator()) dtype; static constexpr bool value = type::value; -}; // an object is callable iff it defines operator() +}; // an object is callable iff it defines operator() -template +template struct is_callable { - // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not + // 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<> +template <> struct plot_impl { - template + template bool operator()(const IterableX& x, const IterableY& y, const std::string& format) { // 2-phase lookup for distance, begin, end - using std::distance; using std::begin; + using std::distance; using std::end; auto xs = distance(begin(x), end(x)); @@ -1671,7 +1914,8 @@ struct plot_impl 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++)); } @@ -1681,57 +1925,72 @@ 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<> +template <> struct plot_impl { - template + template bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) { - if(begin(ticks) == end(ticks)) return true; + 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 +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...); + 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); +inline bool plot(const std::vector& y, const std::string& format = "") +{ + return plot(y, format); } -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); +inline bool plot(const std::vector& x, + const std::vector& y, + const std::map& keywords) +{ + return plot(x, y, keywords); } /* @@ -1742,13 +2001,16 @@ 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 = "") + { assert(x.size() == y.size()); PyObject* kwargs = PyDict_New(); - if(name != "") + if (name != "") PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); PyObject* xarray = get_array(x); @@ -1761,17 +2023,18 @@ 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) + if (res) { - line= PyList_GetItem(res, 0); + 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); @@ -1781,12 +2044,15 @@ class Plot // shorter initialization with name or format only // basically calls line, = plot([], []) Plot(const std::string& name = "", const std::string& format = "") - : Plot(name, std::vector(), std::vector(), format) {} + : Plot(name, std::vector(), std::vector(), format) + { + } - template - bool update(const std::vector& x, const std::vector& y) { + 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 = get_array(x); PyObject* yarray = get_array(y); @@ -1796,44 +2062,43 @@ class Plot PyTuple_SetItem(plot_args, 1, yarray); PyObject* res = PyObject_CallObject(set_data_fct, plot_args); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); return res; } return false; } // 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) + void remove() + { + if (line) { - auto remove_fct = PyObject_GetAttrString(line,"remove"); + auto remove_fct = PyObject_GetAttrString(line, "remove"); PyObject* args = PyTuple_New(0); PyObject* res = PyObject_CallObject(remove_fct, args); - if (res) Py_DECREF(res); + if (res) + Py_DECREF(res); } decref(); } - ~Plot() { - decref(); - } -private: + ~Plot() { decref(); } - void decref() { - if(line) +private: + void decref() + { + if (line) Py_DECREF(line); - if(set_data_fct) + if (set_data_fct) Py_DECREF(set_data_fct); } - PyObject* line = nullptr; PyObject* set_data_fct = nullptr; }; -} // end namespace matplotlibcpp +} // end namespace matplotlibcpp