11

I am developing an math-oriented GUI application in Qt/C++ and would like to embed a Python scripting, including NumPy and Matplotlib. Using Python C API, I finally managed to run a script, retrieve the values from the Python variables, including NumPy arrays etc. But I failed at drawing Matplotlib charts into my Qt/C++ application.

It is better to say, I have managed to save the chart's RGBA buffer to a variable using Python script, then get the value of the variable as a PyObject of buffer type, get the buffer and transform it to QImage then to QPixmap and finally put it into QLabel and display it.

But I am still missing its interactive behaviour, resizing etc. though it seems that it can be done by forwarding Qt mouse events to figure.canvas.button_press_event but it is then getting overly complicated... So I concluded I do not understand the principles of Python embedding well enough. I am missing something obvious.

I found some samples of embedding matplotlib charts into PyQt or PySide (i.e. written in Python) applications where I have seen something like QMainWindow.setCentralWidget(canvas) or layout.addWidget(canvas). Here canvas is FigureCanvasQTAgg object ( http://matplotlib.org/api/backend_qt4agg_api.html ).

This suggests that canvas inherits from QWidget. But when I try mimic this in C++ code using Python's C API, I end with just a PyObject *canvas, not knowing how to trasform it to a QWidget. This is my snippet without the important step:

//draw a figure in Python script called from C++ app
PyRun_SimpleString("import matplotlib\n"
"matplotlib.use('Qt4agg')\n" //use Qt4 backend
"import pylab\n"
"pylab.plot(randn(10))\n" //plot something
"fig = pylab.gcf()\n" //take current figure
"canvas = fig.canvas" //canvas is of FigureCanvasQTAgg type

//get canvas as PyObject
PyObject* m = PyImport_AddModule("__main__");
PyObject* canvas = PyObject_GetAttrString(m, "canvas");
//from what I know, canvas is a PyObject wrapped around an object derived from QWidget

//...
//... here I do not know how to convert canvas (i.e. PyObject) into canvasWidget (i.e. QWidget)???
//... 

//show chart as a widget
MyWindow.setCentralWidget(canvasWidget)

As I wrote, I must be missing something obvious. I googled everywhere but without success. Any help would be very appreciated.

tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • This is a curious question, you want to wrap in c++ the python wrapper of a c++ class ;) You are correct that `FigureCanvasQTAgg` _is_ a `QWidget` object, but I also don't know enough about embedding to get a reference to the underlying QT object out. – tacaswell Sep 08 '13 at 19:44
  • tcaswell - Yes, this is exactly what I would need - extract the reference or pointer or whatever QWidget from PyObject. – HiFile.app - best file manager Sep 08 '13 at 20:10
  • My only suggestion is to look into exactly what `PyQt` or `PySide` are doing underneath. – tacaswell Sep 08 '13 at 20:12
  • Does the posted answer solve your problem? – tacaswell Sep 13 '13 at 22:15
  • I am sorry, for not replying sooner and thank you for your patience. I will check the suggested solution. However I decided othewise and chose the safest way, and reworked my entire app into pure Python+PyQt application which might have some performance drawbacks compared to Qt/C++ but so far it seems satisfactory. Anyway, out of curiosity I will test what you and bks suggested. Thank you for your help. – HiFile.app - best file manager Oct 23 '13 at 13:40
  • I think this question should receive more attention, as an inceasing number of developers (including myself) find it interesting to interface `Matplotlib` with a C++ application, which stands for a better plotting solution than `qwt` or other libraries with under-average rendering capabilities and limited plotting API. For interested people, check this [Github project](https://github.com/lava/matplotlib-cpp) – SAAD Jan 19 '16 at 09:24

1 Answers1

1

For PySide, I suggest reading this comp.lib.qt.pyside thread and also the section on type converters in the PySide docs. I can't vouch for the absolute correctness of this code, but it appears to do what you want.

For PyQt, the same comp.lib.qt.pyside thread links to an example of unwrapping SIP objects which is again exactly what you need.

bks
  • 1,360
  • 6
  • 7
  • 4
    Could you summarize the contents of the link? They look right, but links rot which reduces the long-term usefulness of this answer. – tacaswell Sep 16 '13 at 16:11
  • This is not a meaningful response much less an answer. – Lenz Nov 07 '22 at 01:58