2

I am currently developing a C++ application using Qt and I have to plot some data which is generated by C++ (vectorfields, time-signals correlation matrices etc...). I found the Matplotlib from Python quite nice which is why I want to pass the data from the C++ program to a Python function which will do the plotting. The problem is that the call to the Python function is blocking e.g. it stops the Qt GUI. I currently solve this issue by forking a new process and calling the Python function from the child process.

My question is whether there is a more efficient way of opening a Python Plot from C++ or if forking a new process is pretty much all I can do?

C-Testprogram that calls Python-Plotting-Function:

#include <python3.6/Python.h>
#include <python3.6/listobject.h>
#include <stdlib.h>
#include <fstream>
#include <unistd.h>
#include <math.h>

#define N_LIST 100

using namespace std;

//define some constants for plotting sin(2*pi*50*t)
double f=50;
double ang_frequency=2*M_PI*f;
double dt=1/(f*N_LIST);

int main(int argc,char** argv){
    //set the PYTHONPATH variable to that python can find the Python script containing the plotting function
    char currentdir[200];
    getcwd(currentdir,200);
    printf("%s\n",currentdir);
    if(setenv("PYTHONPATH",currentdir,0)!=0){
        printf("Could not set PYTHONPATH\n");
    };
    //start the python interpreter
    Py_Initialize();
    //load the python module
    PyObject* modulename=PyUnicode_FromString("Module");
    PyObject* module=PyImport_Import(modulename);
    Py_DECREF(modulename);
    if(module!=NULL){
        //load the python function which should do the plotting
        PyObject* py_function=PyObject_GetAttrString(module,"plotFunction");
        //create two python lists for holding the time points and signal points
        PyObject* py_listy=PyList_New(N_LIST);
        PyObject* py_listx=PyList_New(N_LIST);
        //fill the lists with values
        for(int i=0; i<N_LIST; i++){
            double c_currentdouble=sin(i*dt*ang_frequency);
            double c_currenttime=dt*i;
            PyObject* py_currentdoubley=Py_BuildValue("d",c_currentdouble);
            PyObject* py_currenttime=Py_BuildValue("d",c_currenttime);
            PyList_SetItem(py_listy,i,py_currentdoubley);
            PyList_SetItem(py_listx,i,py_currenttime);
        }
        //call the python and pass the data generated in C
        //------------------------------------------------------------------------------------------------------
        if(py_function&&PyCallable_Check(py_function)){
            pid_t pid=fork();
            if(pid==0){
                PyObject* res=PyObject_CallFunctionObjArgs(py_function,py_listx,py_listy,NULL);
                return EXIT_SUCCESS;
            }
        }
        //------------------------------------------------------------------------------------------------------
        else{
            printf("Could not create function object.");
            printf("\n%d",py_function);
            return EXIT_FAILURE;
        }
    }
    else{
        printf("Cannot find module.");
        return EXIT_FAILURE;
    }
    printf("Exiting program\n");
    return EXIT_SUCCESS;
}

Python Script containing plotFunction(argx,argy):

import matplotlib.pyplot as plt
import numpy as np

def plotFunction(argx,argy):
    if type(argx)==list or type(argx)==np.ndarray and type(argy)==list or type(argy)==np.ndarray:
        plt.plot(argx,argy)
        plt.grid()
        plt.show()
    else:
        print("Not all arguments passed are lists. Call failed.")
1
  • For improvement of already working code you should better ask at SE Code Review. Commented Dec 17, 2018 at 20:44

1 Answer 1

1

If you want to stick to python you can call the function in a new thread instead of a whole new process. This is quite easy if you have C++11 std::thread but you can also use QtThread.

An easier way would be to use QtCharts though and plot directly in C++.

A third way would be to save the plot from python to an image and display that image in Qt.

Sign up to request clarification or add additional context in comments.

1 Comment

I think I'll use a QThread instead of forking. But I'll stick with Matplotlib since QCharts doesn't seem to be able to do vector field plots. Thanks for your reply!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.