Skip to content

Is it possible to draw plot into simple buffer? #195

Open

Description

@pktiuk

Is it possible to draw plot into prepared buffer?

char *imgBuff;
//allocate memory for buffer and set size of plot...
plt::drawToBuff(imgBuff);

It would let me using it with some multimedia libraries.

Activity

  1. Raj-Uddin commented on Mar 18, 2025

    @Raj-Uddin

    Have you figured this out?

  2. Raj-Uddin commented on Mar 18, 2025

    @Raj-Uddin

    Alright I've perfectly figured this out, the best and easiest way to do this is to modify the matplotlibcpp.h header file, add this code, right below inline void save(const std::string& filename, const int dpi=0):

    inline std::vector<uint8_t> save_to_buffer(const int dpi = 0) 
    {
        detail::_interpreter::get();
    
        // Import io module
        PyObject* io_module = PyImport_ImportModule("io");
        if (!io_module) throw std::runtime_error("Could not import io module");
    
        // Create a BytesIO object
        PyObject* bytes_io = PyObject_CallMethod(io_module, "BytesIO", nullptr);
        if (!bytes_io) throw std::runtime_error("Could not create BytesIO object");
    
        // Prepare arguments for savefig
        PyObject* args = PyTuple_New(1);
        PyTuple_SetItem(args, 0, bytes_io);
    
        PyObject* kwargs = PyDict_New();
        if (dpi > 0) {
            PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi));
        }
        PyDict_SetItemString(kwargs, "format", PyUnicode_FromString("png"));
    
        // Call savefig with BytesIO object
        PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_save, args, kwargs);
        if (!res) throw std::runtime_error("Call to savefig() failed.");
    
        // Get the value from BytesIO
        PyObject* getvalue = PyObject_CallMethod(bytes_io, "getvalue", nullptr);
        if (!getvalue) throw std::runtime_error("Could not get value from BytesIO");
    
        // Convert the bytes data to a C++ vector
        char* data;
        Py_ssize_t size;
        if (PyBytes_AsStringAndSize(getvalue, &data, &size) == -1) 
        {
            throw std::runtime_error("Could not retrieve data from BytesIO");
        }
        std::vector<uint8_t> buffer(data, data + size);
    
        // Clean up
        Py_DECREF(args);
        Py_DECREF(kwargs);
        Py_DECREF(res);
        Py_DECREF(bytes_io);
        Py_DECREF(getvalue);
        Py_DECREF(io_module);
    
        return buffer;
    }
    

    Here is test example such that, C++ can create a plot using matlibplotcpp, directly store it to buffer, then have OpenCV to access the buffer and view the contents graphically:

    /*
    
    How to compile:
    cl /EHsc /std:c++17 /I C:\Python312\include /I F:\OpenCV_Course\myenv\Lib\site-packages\numpy\_core\include /I F:\AI_Componets\OpenCV\build\install\include matplotlib_display_pics_from_memory.cpp /link /LIBPATH:F:\AI_Componets\OpenCV\build\install\x64\vc17\lib /LIBPATH:C:\Python312\libs python312.lib opencv_core500.lib opencv_imgcodecs500.lib opencv_highgui500.lib opencv_imgproc500.lib
    
    */
    
    
    #define _USE_MATH_DEFINES
    #include <cmath>
    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include "F:\OpenCV_Course\matplotlib-cpp\matplotlibcpp.h"
    #include <vector>
    #include <sstream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    namespace plt = matplotlibcpp;
    
    
    
    int main() {
        try {
    
    
        // Prepare data
        int ncols = 500, nrows = 300;
        std::vector<float> z(ncols * nrows);
        for (int j=0; j<nrows; ++j) {
            for (int i=0; i<ncols; ++i) {
                z.at(ncols * j + i) = std::sin(std::hypot(i - ncols/2, j - nrows/2));
            }
        }
    
        const float* zptr = &(z[0]);
        const int colors = 1;
    
        plt::title("My matrix");
        plt::imshow(zptr, nrows, ncols, colors);
    
            // Call the save_to_buffer function
            std::vector<uint8_t> buffer = plt::save_to_buffer();
    
            // Decode the buffer into an OpenCV Mat object
            cv::Mat image = cv::imdecode(buffer, cv::IMREAD_COLOR);
            if (image.empty()) {
                throw std::runtime_error("Failed to decode image from buffer");
            }
    
            // Display the image using OpenCV
            cv::imshow("Plot", image);
            cv::waitKey(0);
        } catch (const std::exception& e) {
            std::cerr << "Error: " << e.what() << std::endl;
            return 1;
        }
    
        return 0;
    }
    

    Example Output:
    Image

  3. added a commit that references this issue on Dec 7, 2025
  4. lava commented on Nov 4, 2026

    @lava
    Owner

    Thanks for the request! Rendering a plot into memory fits the project: it is just savefig with an io.BytesIO target, so it stays a thin wrapper. The save_to_buffer snippet posted in this thread is a good starting point for a PR. Ideally it would sit next to plt::save, return a std::vector<uint8_t> with the encoded image, take the image format (e.g. "png") and the usual trailing std::map<std::string, std::string> keywords, throw on failure like save does without leaking references on the error paths, and come with a small example. Until then, saving to a temporary file with plt::save(...) and reading it back into your buffer works on master.


    🤖 This triage was made by the project's automated governance process. See the README for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions