19

I'm looking for a clean way to migrate numpy arrays to latex bmatrix. It should work for both 2d arrays and horizontal and vertical 1d array.

Example

A = array([[12, 5, 2],
           [20, 4, 8],
           [ 2, 4, 3],
           [ 7, 1,10]])

print A              #2d array
print A[0]           #horizontal array
print A[:,0, None]   #vertical array

array_to_bmatrix(A)
array_to_bmatrix(A[0])
array_to_bmatrix(A[:,0, None])

Out:

[[12  5  2]
 [20  4  8]
 [ 2  4  3]
 [ 7  1 10]]

[12  5  2]

[[12]
 [20]
 [ 2]
 [ 7]]

\begin{bmatrix} 
 12.000 & 5.000 & 2.000 & \\
 20.000 & 4.000 & 8.000 & \\
 2.000 & 4.000 & 3.000 & \\
 7.000 & 1.000 & 10.000 & \\
\end{bmatrix}

\begin{bmatrix} 
 12.000 & 5.000 & 2.000
\end{bmatrix}

\begin{bmatrix} 
 12.000 & \\
 20.000 & \\
 2.000 & \\
 7.000 & \\
\end{bmatrix}

Attempt of solution

def array_to_bmatrix(array):
    begin = '\\begin{bmatrix} \n'
    data = ''
    for line in array:        
        if line.size == 1:
            data = data + ' %.3f &'%line
            data = data + r' \\'
            data = data + '\n'
            continue
        for element in line:
            data = data + ' %.3f &'%element

        data = data + r' \\'
        data = data + '\n'
    end = '\end{bmatrix}'
    print begin + data + end  

This solution works for vertical and 2d arrays, however it outputs horizontal arrays as vertical ones.

array_to_bmatrix(A[0])

Out:

\begin{bmatrix} 
 12.000 & \\
 5.000 & \\
 2.000 & \\
\end{bmatrix}

13 Answers 13

38

The __str__ method of the numpy array already does most of the formatting for you. Let's exploit that;

import numpy as np

def bmatrix(a):
    """Returns a LaTeX bmatrix

    :a: numpy array
    :returns: LaTeX bmatrix as a string
    """
    if len(a.shape) > 2:
        raise ValueError('bmatrix can at most display two dimensions')
    lines = str(a).replace('[', '').replace(']', '').splitlines()
    rv = [r'\begin{bmatrix}']
    rv += ['  ' + ' & '.join(l.split()) + r'\\' for l in lines]
    rv +=  [r'\end{bmatrix}']
    return '\n'.join(rv)

A = np.array([[12, 5, 2], [20, 4, 8], [ 2, 4, 3], [ 7, 1, 10]])
print bmatrix(A) + '\n'

B = np.array([[1.2], [3.7], [0.2]])
print bmatrix(B) + '\n'

C = np.array([1.2, 9.3, 0.6, -2.1])
print bmatrix(C) + '\n'

This returns:

\begin{bmatrix}
  12 & 5 & 2\\
  20 & 4 & 8\\
  2 & 4 & 3\\
  7 & 1 & 10\\
\end{bmatrix}

\begin{bmatrix}
  1.2\\
  3.7\\
  0.2\\
\end{bmatrix}

\begin{bmatrix}
  1.2 & 9.3 & 0.6 & -2.1\\
\end{bmatrix}
Sign up to request clarification or add additional context in comments.

1 Comment

This has problems for matrices with longer rows -- it will insert '\\' in the middle of a row because str(a) has a maximum line width. To get around this, I replaced str(a) in your bmatrix function with np.array2string(a, max_line_width=np.infty), which allows the rows to be their full length. This also gives more control over other string representation choices, like precision and formatting.
6

Try array_to_latex (pip install). I wrote it for this very reason. Please provide your feedback where it falls short.

It has defaults, but also lets you customize formats (exponential, number of decimal places) and handles complex numbers as well and can "pop" the results right into your clipboard (no need to copy text dumped to the screen).

Some examples in the github repository. https://github.com/josephcslater/array_to_latex

4 Comments

Is there a way to save the string instead of printing it using your tool? I'd like to use this in combination with IPython.display.Math (as in here: stackoverflow.com/questions/48422762/…)
Not at this moment- but pretty simple to do. I'm absolutely slammed right now. Put a watch on the repository- I'll try to fix this in a few weeks when I come up for air.
@Jindra-Helci This works- I had forgotten about it. Not documented well enough. This could be used in the mybinder example on a2l's github page. ` a = a2l.to_ltx(A, frmt = '{:.2f}', arraytype = 'array', mathform = True)`
0.76 release will work better for you. I added a boolean print_out which when set to false will quietly return the latex in the output. Other important cleanups for your use/application. Readme on pypi is one reve behind- oops. Check doc on github repository with examples updated as well as the mybinder notebook, with updated exampled. Please let me know if this works for you.
3

I am not satisfied with using the printed output from Python. The matrix may be too big, which causes wrapping. This is code for to print the LaTeX text for a 2d matrix.

def bmatrix(a):
    text = r'$\left[\begin{array}{*{'
    text += str(len(a[0]))
    text += r'}c}'
    text += '\n'
    for x in range(len(a)):
        for y in range(len(a[x])):
            text += str(a[x][y])
            text += r' & '
        text = text[:-2]
        text += r'\\'
        text += '\n'
    text += r'\end{array}\right]$'

    print text

Which gives this

$\left[\begin{array}{*{16}c}
2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 \\
0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 \\
0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 \\
-1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 & -1 \\
-1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 & 0 \\
0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 & 0 \\
0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 2.01 \\
\end{array}\right]$

Comments

3

Another option is to use sympy: first convert the array to a sympy.Matrix and then use the sympy.latex function.

Comments

1

A further answer, inspired by Roland Smith's answer:

def matToTex(a, roundn=2, matrixType = "b",rowVector = False):
    if type(a) != np.ndarray:
        raise ValueError("Input must be np array")
    if len(a.shape) > 2:
        raise ValueError("matrix can at most display two dimensions")
    if matrixType not in ["b","p"]:
        raise ValueError("matrix can be either type \"b\" or type \"p\"")
    if rowVector:
        if not (len(a.shape) != 1 or a.shape[0] != 1):
            raise ValueError("Cannot rowVector this bad boi, it is not a vector!")
    lines = str(a).splitlines()
    ret = "\n\\begin{"+matrixType+"matrix}\n"
    for line in lines:
        line = re.sub("\s+",",",re.sub("\[|\]","",line).strip())
        nums = line.split(",");
        if roundn != -1:
            nums = [str(round(float(num),roundn)) for num in nums]
        if rowVector:
            ret += " \\\\\n".join(nums)
        else:
            ret += " & ".join(nums)+" \\\\ \n"
    ret += "\n\\end{"+matrixType+"matrix}\n"
    ret = re.sub("(\-){0,1}0.[0]* ","0 ",ret)
    print(ret)

Comments

1

yet another, inspired by Roland Smith's answer support scientific notation format

def bmatrix(a):
    """Returns a LaTeX bmatrix

    :a: numpy array
    :returns: LaTeX bmatrix as a string
    """
    if len(a.shape) > 2:
        raise ValueError('bmatrix can at most display two dimensions')
    temp_string = np.array2string(a, formatter={'float_kind':lambda x: "{:.2e}".format(x)})
    lines = temp_string.replace('[', '').replace(']', '').splitlines()
    rv = [r'\begin{bmatrix}']
    rv += ['  ' + ' & '.join(l.split()) + r'\\' for l in lines]
    rv +=  [r'\end{bmatrix}']
    return '\n'.join(rv)

result:

\begin{bmatrix}
  7.53e-04 & -2.93e-04 & 2.04e-04 & 5.30e-05 & 1.84e-01 & -2.43e-05\\
  -2.93e-04 & 1.19e-01 & 2.96e-01 & 2.19e-01 & 1.98e+01 & 8.61e-03\\
  2.04e-04 & 2.96e-01 & 9.60e-01 & 7.42e-01 & 4.03e+01 & 2.45e-02\\
  5.30e-05 & 2.19e-01 & 7.42e-01 & 6.49e-01 & 2.82e+01 & 1.71e-02\\
  1.84e-01 & 1.98e+01 & 4.03e+01 & 2.82e+01 & 5.75e+03 & 1.61e+00\\
  -2.43e-05 & 8.61e-03 & 2.45e-02 & 1.71e-02 & 1.61e+00 & 7.04e-03\\
\end{bmatrix}

Comments

1

Just to elaborate on macleginn answer.

import numpy as np
import sympy as sym
from IPython.display import display, Math
A = np.array([[12, 5, 2],
       [20, 4, 8],
       [ 2, 4, 3],
       [ 7, 1,10]])
A = sym.Matrix(A)
display(A)

Comments

0

When you do this:

    for line in array:

you are iterating over the first dimension of array. When the array is 1-D, you end up iterating over the values. You need to ensure that array is really 2-D before doing this iteration. One way is to pass the argument through numpy.atleast_2d:

import numpy as np

def array_to_bmatrix(array):
    array = np.atleast_2d(array)
    begin = '\\begin{bmatrix} \n'
    data = ''
    for line in array:

etc.

Comments

0

I've made the attempt to make a comprehensive solution so that individuals don't need to write up even a minimal script to get it done. I've put in flexibility for floats, formatting, complex, and Pandas arrays. Please use, and provide feedback to, (array_to_latex)[https://pypi.org/project/array-to-latex/] .

Comments

0

If you happen to use qiskit by any chance, you may try a sleek method array_to_latex from qiskit.visualization.

See here:

Sample snippet:

from qiskit.visualization import array_to_latex
import numpy as np

x = np.zeros(100).reshape(10,10)


# Max rows and cols = 24
array_to_latex(array=x, prefix='Output = ', max_size=(10,10)) # If max_size not set then matrix will have ellipses
# print latex source only: Source=True
latex_source = array_to_latex(array=x, source=True, max_size=(10,10))

# If you are using Jupyter Notebook: 
from IPython.display import display, Markdown
display(Markdown(latex_source))

Sample output:

enter image description here

Comments

0

In addition, to the answers before, you can generate the latex from the array this way

from IPython.display import *
from numpy import *
A = array([[12, 5, 2],
       [20, 4, 8],
       [ 2, 4, 3],
       [ 7, 1,10]])

latexA = '$$\n' + r'\begin{bmatrix}' + '\n' + (r'\\' + '\n').join('&'.join(str(x) for x in row) for row in A) + '\n' + r'\end{bmatrix}' + '\n' +'$$'
print(latexA)

display(Latex(latexA))

print output is as follows.

$$
\begin{bmatrix}
12&5&2\\
20&4&8\\
2&4&3\\
7&1&10
\end{bmatrix}
$$

1 Comment

The use of joins is a good idea. But your answer does not work. You need two joins, one for the column separators & and one for the row separators \\. I edited your answer :)
0

If you have sympy:

>>> from sympy import Matrix, latex
>>> M = np.array([[1,2],[3,4]])
>>> print(latex(Matrix(M)))
\left[\begin{matrix}1 & 2\\3 & 4\end{matrix}\right]

It's got some other nice utilities to help with this: https://docs.sympy.org/latest/tutorials/intro-tutorial/printing.html

Comments

0

The following is a safe and sound method to print every numpy array, including your integer array and any float array, into LaTex's bmatrix:

Let's say you have a random numpy array:

matrix = np.random.rand(4,4)

which is

array([[0.07758254, 0.03075972, 0.086804  , 0.49218633],
       [0.66657323, 0.24237093, 0.80275257, 0.78427021],
       [0.8932446 , 0.52083966, 0.97440407, 0.19699826],
       [0.71994741, 0.04357679, 0.4385115 , 0.77400596]])

You want to print this matrix into LaTex's \bmatrix command. You may also want to control how many significant figures you want.

You can use the following method to do that:

def print_bmatrix(matrix, precision=0):
    matrix = matrix.tolist()
    print('\\begin{bmatrix}')
    for row in matrix[:-1]:
        print_row(row,precision)
    print_last_row(matrix[-1],precision)
    print('\\end{bmatrix}')

def print_row(row,precision):
    for item in row[:-1]:
        print(format(item,'.'+str(precision)+'f'), end=' & ')
    print(format(row[-1],'.'+str(precision)+'f')+'\\\\')

def print_last_row(row,precision):
    for item in row[:-1]:
        print(format(item,'.'+str(precision)+'f'), end=' & ')
    print(format(row[-1],'.'+str(precision)+'f')) 

Now you can call:

print_bmatrix(matrix, 3)

where 3 stands for 3 significant figures. This gives:

\begin{bmatrix}
0.601 & 0.077 & 0.865 & 0.290\\
0.777 & 0.379 & 0.964 & 0.853\\
0.866 & 0.360 & 0.588 & 0.218\\
0.729 & 0.021 & 0.220 & 0.458
\end{bmatrix}

enter image description here

For your numpy array, which are all integers, you can simply do this:

A = np.array([[12, 5, 2],
           [20, 4, 8],
           [ 2, 4, 3],
           [ 7, 1,10]])
print_bmatrix(A)

This gives:

\begin{bmatrix}
12 & 5 & 2\\
20 & 4 & 8\\
2 & 4 & 3\\
7 & 1 & 10
\end{bmatrix}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.