2

I'd like to re-use a Python script that makes use of matplotlib in interactive mode by embedding a call to it from a C application -- what do I need to do in order to get interactive mode in an embedded Python script working?

I set up an extremely simple example using PyRun_SimpleString(); it works when interactive mode is turned off, but when interactive mode is on the plot window only shows up for a brief interval right before the application ends

#include <Python.h>

int
main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime,sleep\n"
                       "import matplotlib.pyplot as plt\n"
                       "import matplotlib\n"
                       "print(matplotlib.get_backend())\n"
                       "plt.ion()\n"
                       "plt.plot([1,2,3,4,3,5,7])\n"
                       "sleep(5)\n");
    Py_Finalize();
    PyMem_RawFree(program);
    return 0;
}

The backend used by matplotlib is Qt4Agg. When I execute the lines above in the Python interpreter, it behaves as I'd expect. If I change the plt.ion() to a plt.ioff() and put in a plt.show() after the plt.plot() call, I also see the plot.

1 Answer 1

0

I'm assuming when you say, "[w]hen I execute the lines above in the Python interpreter, it behaves as I'd expect," you're referring to running it within the Python command line/REPL. The right way to test one to one behavior with embedded Python would be to instead place your in a python script and then try running it with python script.py.

You'll notice that within a script your code gives a similar problem. I think the trick is to use plt.pause(5) instead of sleep(5), this allows the event loop for the plot GUI to fire and actually draw the window properly (https://stackoverflow.com/a/35119003/11365663).

For REPLs, matplotlib has some extra magic so that the details of the event loop are hidden from you.

This worked for me:

#include <Python.h>

int
main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime,sleep\n"
                       "import matplotlib.pyplot as plt\n"
                       "import matplotlib\n"
                       "print(matplotlib.get_backend())\n"
                       "plt.ion()\n"
                       "plt.plot([1,2,3,4,3,5,7])\n"
                       "plt.pause(5)\n");
    Py_Finalize();
    PyMem_RawFree(program);
    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for this explanation -- the comments you made regarding the even loop made perfect sense and introducing the pause() call did the trick -- thanks for pointing out what was going on under the hood with matplotlib, too. I appreciate your help ...

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.