Boosting MATLAB with Python
... practical findings on incorporating Python.
Published: 2023-01-10

Summary
-
Python functionality can be called from MATLAB with the
py.
syntax. You need to select a Python interpreter in MATLAB and ensure that Python has access to the functionality. -
A Python environment cannot be selected in the same MATLAB function where a
py.
call is made. Thepy.
call must be in another function to prevent the MATLAB interpreter to start the last used Python version. -
Conda
Python environments are not officially supported to be used from MATLAB, but can be setup to function correctly by temporarily modifying MATLAB's 'path' environment variable. Virtual environments are supported since MATLAB R2022b and R2022a - update 4, and can be used in earlier versions by temporarily modifying MATLAB's 'path' environment variable. -
Python
matplotlib
figures can be created from MATLAB and shown in individual figure windows with a little effort. You need to ensurematplotlib
can find the its dependencies by putting them in the environment variables. All created figures can be shown at the same time with thematplotlib.pyplot.show()
function. This function blocks the process until all figures are closed. Alternatively, figures can be exported to image files.
The initial task
One of our clients asked us to unlock a Python module to their MATLAB tool-suite with which they do their analyses. The module would be part of a Conda Python environment, use matplotlib
to visualize results, and would be used from MATLAB R2019a and R2021a.
The tool-suite's startup functions should ensure the correct Python environment is started and that the necessary resources are found.
We have achieved this, but it proved to be more work than we had originally anticipated. In the following sections we will describe some of the steps we took, the difficulties we ran into, and the solutions we used to overcome them.
Selecting a Python interpreter
Python functionality can be called from MATLAB by prepending the Python call with a py.
prefix. The Python interpreter that is used to execute the call, can be set with MATLAB's pyenv function (R2019b and later).
In MATLAB R2019a and before you can use the pyversion function. Please refer to the official documentation for an introduction to these functions.
The pyenv
function has an optional name-value pair input ExecutionMode
that accepts the following options:
InProcess
{default}
runs Python in the same process as MATLAB. Offers the best performance.
It is not possible to change the Python interpreter after MATLAB loads a Python environment
InProcess
. To use another Python interpreter you need to restart MATLAB.
OutOfProcess
runs Python in a separate process, which allows using resources that conflict with MATLAB resources, and prevents MATLAB crashing if the Python process crashes.
Note that changes to the MATLAB environment made with
setenv
are included in theOutOfProcess
Python environment, if these changes were made before Python is started.The
OutOfProcess
Python environment can be terminated with theterminate
function and another one can be startedOutOfProcess
without restarting MATLAB. If yourOutOfProcess
environment was terminated and you make apy.
call, a new process is started from the same Python version.
Note that both ExecutionModes allow for debugging and for reloading modified Python code without restarting MATLAB.
Setting up Python with a function
When your MATLAB - Python code is to be used by others, you may want to include a utility function to ease setting up and loading the Python environment in MATLAB.
Note that you should not use pyenv
(or pyversion
) and make a py.
call in the same MATLAB function. The MATLAB interpreter will parse the py.
statement and load the default Python environment before executing the pyenv
function call. When the pyenv
is executed to load the intended Python environment, MATLAB returns an error as pyenv
cannot replace the Python environment that was loaded on parsing the py.
statement.
So, the following function will result in an error when called:
function startup()
pyenv("version", "C:\Programs\Python\3.8.10\python.exe");
aList = py.list({1, 2});
end
Error using pyenv
Python is loaded. The environment cannot be changed in this MATLAB session. To change the environment, restart MATLAB, and then call > 'pyenv'.
You can prevent this error by putting the py.
statement in another (sub)function:
function startup()
pyenv("version", "C:\Programs\Python\3.8.10\python.exe");
aList = createList();
end
function aList = createList()
aList = py.list({1, 2});
end
Note that this error also does not occur when the createList
function is called from a script file instead of a function or when the commands are executed in the Command Window.
When you are loading Python OutOfProcess
, the error message is different and the Python environment can be changed by using the terminate
function.
Error using pyenv
Python is loaded. The environment cannot be changed while the interpreter is running. To change the environment, call 'terminate(pyenv)> ' then call 'pyenv'.
terminate(pyenv)
The terminate function of MATLAB's PythonEnvironment
class allows for terminating Python processes that were started OutOfProcess
. The Python environment is restarted when you make another py.
call.
InProcess
, Loaded
Python environments cannot be terminated. MATLAB needs to be restarted to select another version.
Error using matlab.pyclient.PythonEnvironment/terminate
Termination not supported for InProcess execution mode.
Note: It is not possible to start an InProcess
Python environment when you have used (and terminated) an OutOfProcess
Python environment. It is possible to start another Python version OutOfProcess
.
Error using pyenv
Python loaded in 'OutOfProcess' mode. To change the 'ExecutionMode' to 'InProcess', restart MATLAB, and then call 'pyenv'.
Fix Python's sys modules attributes
Some Python modules use sys
module attributes containing the path to the Python executable (or its parent folder) to find resources in the Python installation. These paths are different when Python is called from MATLAB, which may cause these modules to error. The fix for this issue is to correct these paths after the Python interpreter is started, as described on MATLAB central.
def fix_sys_attrs(prefix: str, exec_path: str) -> None:
"""Fix sys attributes that were not correctly set when MATLAB started the Python Interface.
Args:
prefix: Path to the Python installation.
exec_path: Path to the Python executable.
"""
sys.prefix = prefix
sys.exec_prefix = prefix
sys.executable = exec_path
Unable to resolve the name py.
At some point you may call one of your own Python functions from MATLAB similar to:
function test()
insert(py.sys.path, int32(0), path_to_test_module);
py.test_module.test_function();
end
and get an error:
Unable to resolve the name py.test_module.test_function.
The MATLAB documentation contains a help page with potential causes and solutions to a problem like this. If none of these fix your problem and you are able to load the module into MATLAB and execute the function via the module object:
mod = py.importlib.import_module('test_module');
mod.test_function();
then the problem may be caused by MATLAB having cached the function as 'unresolvable'. This may be caused by calling functionality of the module in the same MATLAB function file where the Python module is put on the MATLAB and Python path. This results in the MATLAB interpreter looking for the Python module before it can be found.
As a quick workaround the following command should result in the function being directly callable again:
clear classes
(Note that running this command also clears all variables in the current scope.)
Using a Python Virtual Environment
Using a Python virtual environment was not supported in the past. It is supported since MATLAB R2022b and R2022a - Update 4: (MATLAB bug report)
The workaround for using virtual environments in earlier MATLAB versions is to temporarily add the folder containing the Python executable to your system's Path.
pyenv("version", "C:\.venv\test\Scripts\python.exe");
extraPaths = "C:\.venv\test\Scripts\";
setenv("path", strjoin(extraPaths, ";") + ";" + getenv("path"));
Using a Conda environment.
Using a Python environment created with Conda is not supported. By adding folders of the environment to your system path as shown here, it is possible to let MATLAB work with a Conda Python environment. (Note that the example is for Windows. For Unix refer to the Python activate script to see which folders it puts on the path.)
pyenv("version", "C:\Users\me\.conda\envs\test\python.exe");
extraPaths = [
"C:\Users\me\.conda\envs\test"
"C:\Users\me\.conda\envs\test\Library\mingw-w64\bin"
"C:\Users\me\.conda\envs\test\Library\usr\bin"
"C:\Users\me\.conda\envs\test\Library\bin"
"C:\Users\me\.conda\envs\test\Scripts"
"C:\Users\me\.conda\envs\test\bin"
];
setenv("path", strjoin(extraPaths, ";") + ";" + getenv("path"));
Creating matplotlib figures
The matplotlib
module is useful for presenting results graphically. matplotlib
figures can be created and shown from MATLAB by using the py.
syntax. There are a couple of things to consider, which are described in more detail in the following sections:
Ensure Tcl library can be found
To create figures with matplotlib, the Tcl
(and optionally Tk
) library needs to be made available to Python as TCL_LIBRARY
(and TK_LIBRARY
) environment variables. This can be done via MATLAB's setenv()
function. Note that for OutOfProcess
mode these variables should be set before the Python process is started, or be set directly in the os.environ
dictionary through a Python function.
Using another backend
The backend that is used by matplotlib
by default may be suitable for exporting the figures to a file type, but not for showing the figures. The 'agg' backend for instance is meant for exporting to .png files and triggers the following error message when trying to show a figure:
UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.
You can check which backend is used by matplotlib
by running the following command:
py.matplotlib.get_backend()
The Tk
library can be used as matplotlib
backend to show figures on a Tk
canvas, as suggested in this MATLAB Answer. Depending on what is available in your Python installation, you may want to use another backend supported by matplotlib
. To make matplotlib
use the TkAgg
backend run:
py.matplotlib.use('TkAgg');
Note that the Tk
library will need to be added to the environment variable TK_LIBRARY
, similar to what is described in the previous section for the Tcl
library.
Showing figures
The code snippet below creates (but does not show) two simple matplotlib
figure objects.
py.matplotlib.pyplot.plot([1, 2, 3, 4], [1, 2, 3, 4]);
f = py.matplotlib.pyplot.figure();
py.matplotlib.pyplot.plot([1, 2, 3, 4], [4, 3, 2, 1]);
These matplotlib
figures can be shown from MATLAB, but only if the MATLAB process is blocked when the figure windows are created. If the MATLAB process is not blocked, the figures are not shown correctly and MATLAB (or the OutOfProcess
Python process) crashes when the figure window is resized or closed.
The following matplotlib
function triggers all created figures to be shown in separate windows. The MATLAB process will be blocked until all matplotlib
figure windows are closed.
py.matplotlib.pyplot.show()
The same function can be called with an input argument to not block the MATLAB process, but this results in empty figure windows and MATLAB crashes when the windows are resized or closed.
py.matplotlib.pyplot.show(pyargs('block', false));
In OutOfProcess
mode it is also not possible to show matplotlib
figures without blocking the MATLAB process.
The show
method of a matplotlib
figure object will try to show the figure without blocking the MATLAB process, causing the figure to not be created correctly and MATLAB to potentially crash. The function does not have an optional input argument with which the MATLAB process can be blocked, so you need to use the matplotlib.pyplot.show()
function to be able to show matplotlib
figures from MATLAB.