Calling Python from MATLAB

Now that the recipe book is available for both MATLAB and Python, many Python users will also look into the MATLAB version and discover the beauty of the older sister of Python. There is hope for these people, especially if they want to switch: you can call Python in MATLAB! Here is how.

We first have to link MATLAB with the Python interpreter when we first use Python with MATLAB. Depending on the path to the Python interpreter on your harddrive you have to adapt this command:
pyenv('Version','~/opt/anaconda3/bin/python')

After that, we have four Options 1–4 to use Python commands and scripts in MATLAB.

Option 1

We can run Python commands with the MATLAB command pyrun. In this example the output variable d is stored in the MATLAB workspace. Typing
d = pyrun("c = a**2","c",a=2)

yields the output

d =

     4

in the Command Window of MATLAB.

Option 2

Alternatively, we can import a Python package such as NumPy and then use Python commands in MATLAB. First import NumPy by using
np = py.importlib.import_module('numpy')
which yields
np =

  Python module with properties:

                        fft: [1×1 py.module]
                        eye: [1×1 py.function]
    format_float_scientific: [1×1 py.function]
                 array_repr: [1×1 py.function]
                       str_: [1×1 py.type]

                        (cont'd)
We can now use NumPy commands like in Python
A = np.array([[2,4,3,7],
             [9,3,-1,2],
             [1,9,3,7],
             [6,6,3,-2]])
which yields
A =

  Python ndarray:

  2   4   3   7
  9   3  -1   2
  1   9   3   7
  6   6   3  -2

Use details function to view the properties of
the Python object.

Use double function to convert to a MATLAB array.
We can use the details command to learn more about A. As we see A is stored in the MATLAB workspace as a Python NumPy ndarray
details(A)
which yields
py.numpy.ndarray handle with properties:

        T: [1×1 py.numpy.ndarray]
     base: [1×1 py.NoneType]
   ctypes: [1×1 py.numpy.core._internal._ctypes]
     data: [1×4 py.memoryview]
    dtype: [1×1 py.numpy.dtype[float64]]
    flags: [1×1 py.numpy.core.multiarray.flagsobj]
     flat: [1×1 py.numpy.flatiter]
     imag: [1×1 py.numpy.ndarray]
 itemsize: [1×1 py.int]
   nbytes: [1×1 py.int]
     ndim: [1×1 py.int]
     real: [1×1 py.numpy.ndarray]
    shape: [1×2 py.tuple]
     size: [1×1 py.int]
  strides: [1×2 py.tuple]

Methods, Events, Superclasses
Also the MATLAB whos commands gives you this information:
whos("A")
which yields
Name   Size   Bytes   Class            Attributes

A      1x1        8   py.numpy.ndarray
We can be use MATLAB commands with the ndarray A. The result is a MATLAB double array. However, it ignores the 3×4 dimension of A and gives one single value back. Typing
m1 = mean(A)
yields
m1 =

      3.8750
We can also use the MATLAB command int64 or double to convert it to a MATLAB array and then use it with MATLAB commands. This of course follows the MATLAB rules that functions work on columns and therefore we get four values back for the mean. Typing
C = double(A)
m2 = mean(C)
yields
C =

     2    4    3    7
     9    3   -1    2
     1    9    3    7
     6    6    3   -2

m2 =

     4.5000  5.5000  2.0000  3.5000

Option 3

We can run a Python script with the filename py_example_script and the following content
import numpy as np
B = np.array([[2,4,3,7],
              [9,3,-1,2],
              [1,9,3,7],
              [6,6,3,-2]])
print(B)
np.who()
import scipy.io as sio 
sio.savemat('mydata.mat', {'B':B})
Herein, we first load NumPy, then create and print B, and display the content of the workspace using np.who(). We can pass B from the Python workspace to the MATLAB workspace using a solution by Eric Condamine in the MATLAB Answers. According to this we first save it as a .mat file using the io module from SciPy and then load it into the MATLAB workspace using load. We can run the script using pyrun or pyrunfile. Using
pyrunfile("py_example_script.py")

load mydata.mat
yields
[[ 2  4  3  7]
 [ 9  3 -1  2]
 [ 1  9  3  7]
 [ 6  6  3 -2]]

Name    Shape    Bytes    Type
=====================================
B       4 x 4    128      int64

Upper bound on total bytes = 128

We can then load the data from data.mat using

B = load('mydata.mat')

which loads the data into the MATLAB workspace.

Option 4

We can also create a local module py_example_module
def py_example_module():
   ''' Example Module to demonstrate
   the use of user-created module'''
   print('Example Module Executed')
   import numpy as np
   B = np.array([[2,4,3,7],
   [9,3,-1,2],
   [1,9,3,7],
   [6,6,3,-2]])
   return B
and call it from the MATLAB script using 
pyrun("from py_example_module import py_example_module")
pyrun("help(py_example_module)")
D = pyrun("B = py_example_module()","B")
which yields
Help on function py_example_module in module
py_example_module:

py_example_module()
   Example Module to demonstrate
   the use of user-created module

Example Module Executed

D =

   Python ndarray:

   2 4 3 7
   9 3 -1 2
   1 9 3 7
   6 6 3 -2

Use details function to view the properties of
the Python object.

Use int64 function to convert to a MATLAB array.
as the output.

References

Trauth, M.H. (2022) Python Recipes for Earth Sciences – First Edition. Springer International Publishing, ~453 p., Supplementary Electronic Material, Hardcover, ISBN 978-3-031-07718-0.

Trauth, M.H. (2021) MATLAB Recipes for Earth Sciences – Fifth Edition. Springer International Publishing, ~517 p., Supplementary Electronic Material, Hardcover, ISBN: 978-3-030-38440-1.