4
$\begingroup$

I use Blender to explore and render some data that I have in real time.

Besides that, I also have an interactive matplotlib application that further helps me explore and report on the data.

How can I integrate my matplotlib into Blender, so I can use both of them in real time?

$\endgroup$
7
$\begingroup$

This answer reports the best solution I found so far, I'll be happy to hear from feedback or better alternatives:


I wanted to integrate matplotlib into Blender in its own space, but sadly learned that the Blender 2.80 API can't (yet) create new space types.

Therefore the solution for me was to let Blender's Python3.7 interpreter run a separate matplotlib window in a child process (see image).

enter image description here

For that, I had to do the following things:

  1. Make sure import tkinter works (here how I did it, no root privileges needed). With that, it should be possible to <BLENDERS_PYTHON> -m pip install matplotlib and import it. Note that running matplotlib in plt.ioff() mode blocked Blender, and running it in .ion() mode did nothing. Running it on a child process solved it for me.

  2. Make sure multiprocessing.Queue() can be instantiated (In my Ubuntu17 system, this required to copy the _multiprocessing.so file from my non-Blender lib-dynload Python environment.

Now running the following from the Blender interpreter should spawn a child process, that interactively reacts to any changes that the Blender user makes to queue:

import matplotlib.pyplot as plt
import multiprocessing as mp
import numpy

def worker(q):
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ln, = ax.plot([], [])
    fig.canvas.draw()   # draw and show it
    plt.show(block=False)
    i = 0
    while True:
        obj = q.get()
        n = obj + 0
        print("sub : got:", n)
        lnx, lny = ln.get_xdata(), ln.get_ydata()
        ln.set_xdata(numpy.append(lnx, i))
        ln.set_ydata(numpy.append(lny, n))
        ax.relim()
        ax.autoscale_view(True,True,True)
        fig.canvas.draw()
        i += 1

queue = mp.Queue()
p = mp.Process(target=worker, args=(queue,))
p.start()

Once the window is open and listening, add entries to the plot, for example like this:

queue.put(bpy.context.scene.frame_current)

The new entry will be interactively incorporated to the plot. Once you are done, simply kill the process with:

p.terminate()

Hope this helps!
Cheers,
Andres


| improve this answer | |
$\endgroup$
  • $\begingroup$ Missed this, and have done it somewhat differently. Can specify a backend other than tkinter .This gives a list matplotlib.rcsetup.interactive_bk to test against those available. On linux I use GTk3Agg $\endgroup$ – batFINGER Mar 2 at 12:49
  • $\begingroup$ Thanks for your feedback, as always very valuable and appreciated $\endgroup$ – fr_andres Mar 3 at 21:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.