5
$\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$

2 Answers 2

8
$\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


$\endgroup$
2
  • $\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, 2020 at 12:49
  • $\begingroup$ Thanks for your feedback, as always very valuable and appreciated $\endgroup$
    – fr_andres
    Mar 3, 2020 at 21:16
0
$\begingroup$

I use matplotlib with blender, in both distributed addons and in stand-alone scripting solutions. Let me give an updated answer that me and the users of my addon have converged on is the overall best solution. Will outline why we feel that way at the end.

In short:

  • install Tornado webserver, and
  • change the default backend to webAgg

here are the steps to do this for a complete beginner (Blender 3.6.x). This assumes that you want to use the bundled Blender python interpreter. If you preferr your own blender interpreter, that is possible too, but requires some more steps involving deleting the folder of the bundled interpreter (at which point Blender reverts to the system version)

  1. Find the location of the bundled interpreter. From inside the Blender scripting tab, find the console and run:

    import sys

    print(sys.exec_prefix)

  2. setup the environment. open a terminal (for windows and mac the procedure is nearly identical):

    cd <interpreter_folder>

    bin/python3.10 -m ensurepip

    bin/python3.10 -m pip install --upgrade pip

    bin/python3.10 -m pip install tornado

    bin/python3.10 -m pip install matplotlib

  3. set "WebAgg" as the default interpreter:

    sed -i 's/#backend: Agg/backend: WebAgg/g' lib/python3.10/site-packages/matplotlib/mpl-data/matplotlibrc

    NOTE: above is a SED command in Linux. It modifies the file "matplotlibrc". In Windows, you can find the file manually, and modify it. Instructions are in the file, look for the line with "## * BACKENDS", that explains how to do it.

After you have done these steps, every regular python snippet you have that runs pyplot should run flawlessly inside the scripting tab in Blender. Although, it will run through the webbrowser. You will still have the same interactive power with your plots as you do in other environments (zoom, save figure, get coordinates etc)

Why is this the superior solution? This is verified to work on every OS, and there is every indication that it will continue to do so in the future. This circumvents the need for a secondary process/thread, by letting it be routed through Tornado, via webAgg backend. This is important, because even if you do get a solution up and running on some OS, with some particular backend... you can expect there to be instabilities, if not in todays version of Blender then tomorrows. I have seen this happen, and lost a lot of time banging my head trying to find whats wrong.

Finally, this is the only solution that allows you to directly use the same code snippets from your other work into blender without some kind of modification. If you are working with alot of code that you want to run, then even trivial porting efforts to special solutions are to be avoided.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .