Numpy 2d and 1d array to latex bmatrix
Question:
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}
Answers:
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.
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}
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]$
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
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/] .
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}
$$
Another option is to use sympy: first convert the array to a sympy.Matrix and then use the sympy.latex function.
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)
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}
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:
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)
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}
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.
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}
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]$
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
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/] .
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}
$$
Another option is to use sympy: first convert the array to a sympy.Matrix and then use the sympy.latex function.
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)
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}
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:
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)