在C++中嵌入Matplotlib

11

我正在使用C++代码从套接字读取消息,并尝试使用matplotlib进行交互式绘图,但似乎Python代码将阻止主线程,无论我是使用 show() 还是 ion()draw()。在Python中,ion()draw() 不会阻塞。

有没有什么方法可以在C++代码中与matplotlib进行交互式绘图?

如果能提供一个示例就太好了。

非常感谢。


1
你目前做了什么事情是不起作用的?你如何将数据导入Python?实际上你正在尝试做什么并不是很清楚。例如,你是在尝试从C++代码中获取数据并使用IPython进行绘图吗? - Henry Gomersall
1
啊,我猜这与你的另一个问题有关? - Henry Gomersall
嗨,我解决了另一个问题的答案。这个问题涉及在C++中使用matplotlib,C++代码读取数据,并调用matplotlib以交互方式绘制接收到的数据。我调用类似以下的内容: PyRun_SimpleString("import pylab"); PyRun_SimpleString("pylab.ion()"); PyRun_SimpleString("pylab.plot(range(5))"); PyRun_SimpleString("pylab.draw()"); 即使使用draw()而非show(),也会阻塞主C++线程。 - bbc
所以这些调用是在新线程中进行的吗?听起来你正在与全局解释器锁不利地交互。不幸的是,我不知道非常高级层次的库如何与GIL交互。我怀疑它会在调用返回时获取并归还它。它会返回吗?如果你只是使用Python绘图,为什么不将数据传输到Python进程中? - Henry Gomersall
3
好的,我理解你想要使用一些C++库,但希望在Python中绘制数据?你不能反过来做吗 - 从Python中调用C++库?这样做更容易,并且更为广泛地被理解。 - Henry Gomersall
显示剩余3条评论
1个回答

7
您也可以尝试创建一个新线程来调用阻塞函数,以便它不会在主程序循环中阻塞IO。使用线程对象数组并循环查找未使用的线程,创建一个线程来执行阻塞调用,并有另一个线程在完成时加入它们。 此代码是我快速拼凑出来的,以演示如何使用线程为阻塞函数获取伪异步行为......我没有编译它或很好地检查它,只是为了向您展示如何完成这一点。
#include <pthread.h>
#include <sys/types.h>
#include <string>
#include <memory.h>
#include <malloc.h>
#define MAX_THREADS 256 // Make this as low as possible!
using namespace std;
pthread_t PTHREAD_NULL;
typedef string someTypeOrStruct;
class MyClass
{
    typedef struct
    {
        int id;
        MyClass *obj;
        someTypeOrStruct input;
    } thread_data;

    void draw();    //Undefined in this example
    bool getInput(someTypeOrStruct *);  //Undefined in this example
    int AsyncDraw(MyClass * obj, someTypeOrStruct &input);
    static void * Joiner(MyClass * obj);
    static void * DoDraw(thread_data *arg);
    pthread_t thread[MAX_THREADS], JoinThread;
    bool threadRunning[MAX_THREADS], StopJoinThread;

    bool exitRequested;
public:
    void Main();
};

bool MyClass::getInput(someTypeOrStruct *input)
{
}

void MyClass::Main()
{
    exitRequested = false;
    pthread_create( &JoinThread, NULL, (void *(*)(void *))MyClass::Joiner, this);

    while(!exitRequested)
    {
        someTypeOrStruct tmpinput;
        if(getInput(&tmpinput))
            AsyncDraw(this, tmpinput);
    }

    if(JoinThread != PTHREAD_NULL)
    {
        StopJoinThread = true;
        pthread_join(JoinThread, NULL);
    }
}

void *MyClass::DoDraw(thread_data *arg)
{
    if(arg == NULL) return NULL;
    thread_data *data = (thread_data *) arg;
    data->obj->threadRunning[data->id] = true;
    // -> Do your draw here <- //
    free(arg);
    data->obj->threadRunning[data->id] = false; // Let the joinThread know we are done with this handle...
}

int MyClass::AsyncDraw(MyClass *obj, someTypeOrStruct &input)
{
    int timeout = 10; // Adjust higher to make it try harder...
    while(timeout)
    {
        for(int i = 0; i < MAX_THREADS; i++)
        {
            if(thread[i] == PTHREAD_NULL)
            {
                thread_data *data = (thread_data *)malloc(sizeof(thread_data));
                if(data)
                {
                    data->id = i;
                    data->obj = this;
                    data->input = input;

                    pthread_create( &(thread[i]), NULL,(void* (*)(void*))MyClass::DoDraw, (void *)&data);
                    return 1;
                }
                return 0;
            }
        }
        timeout--;
    }
}

void *MyClass::Joiner(MyClass * obj)
{
    obj->StopJoinThread = false;
    while(!obj->StopJoinThread)
    {
        for(int i = 0; i < MAX_THREADS; i++)
            if(!obj->threadRunning[i] && obj->thread[i] != PTHREAD_NULL)
            {
                pthread_join(obj->thread[i], NULL);
                obj->thread[i] = PTHREAD_NULL;
            }
    }
}

int main(int argc, char **argv)
{
    MyClass base;
    base.Main();
    return 0;
}

这样你就可以在绘制过程中继续接受输入。
修复了上面的代码,确保添加了-lpthread参数才能编译通过。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接