Numpy has many nice features for formatted output, but something I miss is the ability to print more than one array/matrix on the same line. What I mean is easiest to explain with an example. Given the following code:
A = np.random.randint(10, size = (4, 4))
B = np.random.randint(10, size = (4, 4))
niceprint(A, "*", B, "=", A @ B)
How can you implement niceprint
so that it prints the following on the console?
[[7 1 0 4] [[8 6 2 6] [[ 80 45 54 83]
[8 1 5 8] * [0 3 8 5] = [147 91 123 140]
[3 7 2 4] [7 8 7 3] [ 62 55 108 95]
[8 8 2 8]] [6 0 8 9]] [126 88 158 166]]
Numpy has many nice features for formatted output, but something I miss is the ability to print more than one array/matrix on the same line. What I mean is easiest to explain with an example. Given the following code:
A = np.random.randint(10, size = (4, 4))
B = np.random.randint(10, size = (4, 4))
niceprint(A, "*", B, "=", A @ B)
How can you implement niceprint
so that it prints the following on the console?
[[7 1 0 4] [[8 6 2 6] [[ 80 45 54 83]
[8 1 5 8] * [0 3 8 5] = [147 91 123 140]
[3 7 2 4] [7 8 7 3] [ 62 55 108 95]
[8 8 2 8]] [6 0 8 9]] [126 88 158 166]]
Share
Improve this question
asked Mar 28 at 10:44
Gaslight Deceive SubvertGaslight Deceive Subvert
20.5k20 gold badges91 silver badges129 bronze badges
2
|
2 Answers
Reset to default 1It may need similar method like in answer for
python - How to place tables next to each other with tabulate - Stack Overflow
it needs to convert all arrays to strings and split them to lists of lines, and next it needs zip()
or better zip_longest(..., fillvalue="")
to group first line (and print them as one string, second lines (and print them as string, with *
and =
), etc.
Because last line has longer (because it has closing ]
at the end) so I use f-string with {variable:length}
to set extra space in previous lines.
It also adds empty lines below array A to put array B in correct place
Because arrays may have different number of lines so it is good to use zip_longest()
instead of zip()
and use fillvalue=''
to put missing lines.
To show this problem I use 4x6
and 6x4
instead of 4x4
import numpy as np
from itertools import zip_longest
A = np.random.randint(10, size = (4, 6))
B = np.random.randint(10, size = (6, 4))
C = A@B
a = str(A).split('\n')
b = str(B).split('\n')
c = str(C).split('\n')
a_len = len(a[0]) + 1
b_len = len(b[0]) + 1
#c_len = len(c[0]) + 1
for index, (x, y, z) in enumerate(zip_longest(a, b, c, fillvalue='')):
if index == 1:
print(f'{x:{a_len}} * {y:{b_len}} = {z}')
else:
print(f'{x:{a_len}} {y:{b_len}} {z}')
Result:
[[4 3 0 5 1 6] [[8 3 5 8] [[ 89 137 104 94]
[6 3 5 7 3 0] * [5 9 8 6] = [128 148 104 149]
[6 6 6 1 7 6] [9 5 6 5] [178 194 178 148]
[9 8 0 3 2 8]] [2 9 2 7] [162 200 183 155]]
[2 5 2 3]
[5 8 8 1]]
EDIT:
If you want to center operator then you need height
and calculate center
and use it with index
height = max(len(a), len(b), len(c))
center = round(height/2)-1 # `round(height/2)` gives better output than `height//2`
# ... code
if index == center:
print(f'{x:<{a_len}} * {y:{b_len}} = {z}')
# ... code
Result:
[[4 8 0 0 5 2] [[5 9 9 4] [[128 96 87 122]
[9 4 0 6 8 3] [9 3 2 7] [161 191 180 155]
[4 9 7 8 9 3] * [0 7 8 9] = [193 228 218 245]
[7 6 6 6 8 1]] [4 7 6 2] [153 205 204 205]]
[4 4 5 8]
[8 8 5 5]]
BTW: You could try to use height-len(a)
, etc. add empty rows before array - to center also arrays.
Because it works with strings so it doesn't matter if you have integer of float values
# float values
A = np.random.randint(10, size = (4, 6)) / 10
B = np.random.randint(10, size = (6, 4)) / 10
Result:
[[0.3 0.3 0.3 0.9 0.2 0.6] [[0.5 0.3 0.2 0.5] [[0.3 0.9 0.65 1.31]
[0.2 0.7 0.2 0.5 0.4 0.8] [0.1 0.6 0.6 0.9] [0.33 1.3 1. 1.79]
[0.3 0. 0.1 0. 0.9 0.9] * [0. 0.7 0.1 0.9] = [0.33 1.33 0.7 1.41]
[0.4 0. 0.4 0.6 0.4 0.5]] [0. 0. 0. 0. ] [0.3 0.96 0.46 1.17]]
[0. 0.9 0.1 0.4]
[0.2 0.4 0.6 0.9]]
I don't have example with n-dimention array but it should also work.
It may need to get lenght of last element in list (and without +1
)
a_len = len(a[-1])
b_len = len(b[-1])
Full working code used for tests with different shapes, integer or float values and with N-dimension
import numpy as np
from itertools import zip_longest
def niceprint(A, op, B, C):
a = str(A).split('\n')
b = str(B).split('\n')
c = str(C).split('\n')
a_len = len(a[-1])
b_len = len(b[-1])
height = max(len(a), len(b), len(c))
center = round(height/2)-1 # `round(height/2)` gives better position than `height//2`
for index, (x, y, z) in enumerate(zip_longest(a, b, c, fillvalue='')):
if index == center:
print(f'{x:<{a_len}} {op} {y:{b_len}} = {z}')
else:
print(f'{x:<{a_len}} {y:{b_len}} {z}')
# ---
def example1():
A = np.random.randint(10, size = (4, 6))
B = np.random.randint(10, size = (6, 4))
C = A@B
niceprint(A, '*', B, C)
def example2():
A = np.random.randint(10, size = (3, 3, 3)) / 10
B = np.random.randint(10, size = (3, 3, 3)) / 10
C = A+B
niceprint(A, '+', B, C)
def example3():
A = np.random.randint(10, size = (2, 3, 3, 2)) / 10
B = np.random.randint(10, size = (2, 3, 3, 2)) / 10
C = A+B
niceprint(A, '+', B, C)
#example1()
#example2()
example3()
Don't write it yourself; use something common and off-the-shelf like Sympy.
import numpy as np
import sympy
A = sympy.Matrix(np.random.randint(10, size=(4, 4)))
B = sympy.Matrix(np.random.randint(10, size=(4, 4)))
sympy.pretty_print(
sympy.Eq(
sympy.MatMul(A, B),
A @ B,
)
)
⎡4 2 1 5⎤ ⎡3 0 7 7⎤ ⎡77 54 42 58 ⎤
⎢ ⎥ ⎢ ⎥ ⎢ ⎥
⎢1 6 5 1⎥ ⎢9 5 0 1⎥ ⎢76 82 29 57 ⎥
⎢ ⎥⋅⎢ ⎥ = ⎢ ⎥
⎢3 3 7 0⎥ ⎢2 9 4 8⎥ ⎢50 78 49 80 ⎥
⎢ ⎥ ⎢ ⎥ ⎢ ⎥
⎣7 6 2 8⎦ ⎣9 7 2 4⎦ ⎣151 104 73 103⎦
zip()
to group first lines from all arrays, second lines, third lines, etc. and display all first lines as one string, next all second lines as one string, etc. – furas Commented Mar 28 at 14:35