Numpy 2d and 1d array to latex bmatrix
Asked Answered
A

13

18

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}
Aquiline answered 16/6, 2013 at 1:0 Comment(0)
L
36

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}
Lyris answered 16/6, 2013 at 9:15 Comment(1)
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.Copp
T
5

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

Twoseater answered 24/12, 2018 at 13:13 Comment(4)
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: #48423262)Onomasiology
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.Twoseater
@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)`Twoseater
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.Twoseater
A
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]$
Apophasis answered 14/4, 2017 at 13:56 Comment(0)
G
3

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

Gammer answered 10/2, 2020 at 19:26 Comment(0)
S
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)
Septemberseptembrist answered 15/12, 2020 at 14:49 Comment(0)
H
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}
Helton answered 15/1, 2021 at 10:25 Comment(0)
I
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)
Induct answered 6/9, 2022 at 20:37 Comment(0)
C
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.

Copulate answered 16/6, 2013 at 5:56 Comment(0)
T
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/] .

Twoseater answered 10/12, 2019 at 15:16 Comment(0)
I
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}
$$
Inchoate answered 30/12, 2019 at 3:21 Comment(1)
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 :)Acord
P
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

Phono answered 16/8, 2022 at 5:49 Comment(0)
C
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

Clawson answered 31/1, 2024 at 21:56 Comment(0)
T
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}
Thetisa answered 17/4, 2024 at 15:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.