Pretty printing of the numpy ndarrays
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
Following this idea for pretty printing of numpy ndarrays, I have developed a very primitive prototype:
def ndtotext(A, w=None, h=None):
if A.ndim==1:
if w == None :
return str(A)
else:
s ='['+' '*(max(w[-1],len(str(A[0])))-len(str(A[0]))) +str(A[0])
for i,AA in enumerate(A[1:]):
s += ' '*(max(w[i],len(str(AA)))-len(str(AA))+1)+str(AA)
s +='] '
elif A.ndim==2:
w1 = [max([len(str(s)) for s in A[:,i]]) for i in range(A.shape[1])]
w0 = sum(w1)+len(w1)+1
s= u'u250c'+u'u2500'*w0+u'u2510' +'n'
for AA in A:
s += ' ' + ndtotext(AA, w=w1) +'n'
s += u'u2514'+u'u2500'*w0+u'u2518'
elif A.ndim==3:
h=A.shape[1]
s1=u'u250c' +'n' + (u'u2502'+'n')*h + u'u2514'+'n'
s2=u'u2510' +'n' + (u'u2502'+'n')*h + u'u2518'+'n'
strings=[ndtotext(a)+'n' for a in A]
strings.append(s2)
strings.insert(0,s1)
s='n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
return s
for example:
shape = 4, 5, 3
C=np.random.randint(10000, size=np.prod(shape)).reshape(shape)
print(ndtotext(C))
┌┌────────────────â”Â┌────────────────â”Â┌────────────────â”Â┌────────────────â”Ââ”Â
│ [9298 4404 1759] [5426 3488 9267] [8884 7721 579] [6872 4226 1858] │
│ [6723 271 8466] [9885 6760 8949] [ 295 7422 5659] [5322 4239 7446] │
│ [7156 6077 9390] [2712 6379 2832] [6956 626 5534] [ 142 4090 6390] │
│ [9377 9033 1953] [8986 3791 4538] [2466 8572 662] [1528 8922 9656] │
│ [1449 7319 3939] [7350 9619 928] [7542 4704 1477] [ 980 6037 869] │
└└────────────────┘└────────────────┘└────────────────┘└────────────────┘┘
I would appreciate if you could review this code and let me know how I can improve it.
What I hope to see:
- possible mistakes or cases to break the code
- how to make it faster, more performant, pythonic
- how to extend it to higher dimensions
python numpy formatting ascii-art unicode
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
 |Â
show 1 more comment
up vote
6
down vote
favorite
Following this idea for pretty printing of numpy ndarrays, I have developed a very primitive prototype:
def ndtotext(A, w=None, h=None):
if A.ndim==1:
if w == None :
return str(A)
else:
s ='['+' '*(max(w[-1],len(str(A[0])))-len(str(A[0]))) +str(A[0])
for i,AA in enumerate(A[1:]):
s += ' '*(max(w[i],len(str(AA)))-len(str(AA))+1)+str(AA)
s +='] '
elif A.ndim==2:
w1 = [max([len(str(s)) for s in A[:,i]]) for i in range(A.shape[1])]
w0 = sum(w1)+len(w1)+1
s= u'u250c'+u'u2500'*w0+u'u2510' +'n'
for AA in A:
s += ' ' + ndtotext(AA, w=w1) +'n'
s += u'u2514'+u'u2500'*w0+u'u2518'
elif A.ndim==3:
h=A.shape[1]
s1=u'u250c' +'n' + (u'u2502'+'n')*h + u'u2514'+'n'
s2=u'u2510' +'n' + (u'u2502'+'n')*h + u'u2518'+'n'
strings=[ndtotext(a)+'n' for a in A]
strings.append(s2)
strings.insert(0,s1)
s='n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
return s
for example:
shape = 4, 5, 3
C=np.random.randint(10000, size=np.prod(shape)).reshape(shape)
print(ndtotext(C))
┌┌────────────────â”Â┌────────────────â”Â┌────────────────â”Â┌────────────────â”Ââ”Â
│ [9298 4404 1759] [5426 3488 9267] [8884 7721 579] [6872 4226 1858] │
│ [6723 271 8466] [9885 6760 8949] [ 295 7422 5659] [5322 4239 7446] │
│ [7156 6077 9390] [2712 6379 2832] [6956 626 5534] [ 142 4090 6390] │
│ [9377 9033 1953] [8986 3791 4538] [2466 8572 662] [1528 8922 9656] │
│ [1449 7319 3939] [7350 9619 928] [7542 4704 1477] [ 980 6037 869] │
└└────────────────┘└────────────────┘└────────────────┘└────────────────┘┘
I would appreciate if you could review this code and let me know how I can improve it.
What I hope to see:
- possible mistakes or cases to break the code
- how to make it faster, more performant, pythonic
- how to extend it to higher dimensions
python numpy formatting ascii-art unicode
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1
How many dimensions does this work with? 1-3.
– Peilonrayz
2 hours ago
@Peilonrayz this one works 1-3 but the HTML version developed by others might work for further dimensions too. I haven't checked. It would be great if we could extend this to all dimensions. I guess doing some text/string work plus recursion this should be doable.
– Foad
2 hours ago
1
Can you modify your example to actually include how to call your function? I.e. what shouldw
look like?
– Graipher
1 hour ago
1
@Foad: Well, it is mostly trivial, but for the 1D case it is not so clear to me what and if anything should be passed forw
.
– Graipher
1 hour ago
1
@Graipher my apologies. yeah the w thing is very badly implemented. I'm actually very embarrassed by it. please help me know how if you can think of a better approach.
– Foad
1 hour ago
 |Â
show 1 more comment
up vote
6
down vote
favorite
up vote
6
down vote
favorite
Following this idea for pretty printing of numpy ndarrays, I have developed a very primitive prototype:
def ndtotext(A, w=None, h=None):
if A.ndim==1:
if w == None :
return str(A)
else:
s ='['+' '*(max(w[-1],len(str(A[0])))-len(str(A[0]))) +str(A[0])
for i,AA in enumerate(A[1:]):
s += ' '*(max(w[i],len(str(AA)))-len(str(AA))+1)+str(AA)
s +='] '
elif A.ndim==2:
w1 = [max([len(str(s)) for s in A[:,i]]) for i in range(A.shape[1])]
w0 = sum(w1)+len(w1)+1
s= u'u250c'+u'u2500'*w0+u'u2510' +'n'
for AA in A:
s += ' ' + ndtotext(AA, w=w1) +'n'
s += u'u2514'+u'u2500'*w0+u'u2518'
elif A.ndim==3:
h=A.shape[1]
s1=u'u250c' +'n' + (u'u2502'+'n')*h + u'u2514'+'n'
s2=u'u2510' +'n' + (u'u2502'+'n')*h + u'u2518'+'n'
strings=[ndtotext(a)+'n' for a in A]
strings.append(s2)
strings.insert(0,s1)
s='n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
return s
for example:
shape = 4, 5, 3
C=np.random.randint(10000, size=np.prod(shape)).reshape(shape)
print(ndtotext(C))
┌┌────────────────â”Â┌────────────────â”Â┌────────────────â”Â┌────────────────â”Ââ”Â
│ [9298 4404 1759] [5426 3488 9267] [8884 7721 579] [6872 4226 1858] │
│ [6723 271 8466] [9885 6760 8949] [ 295 7422 5659] [5322 4239 7446] │
│ [7156 6077 9390] [2712 6379 2832] [6956 626 5534] [ 142 4090 6390] │
│ [9377 9033 1953] [8986 3791 4538] [2466 8572 662] [1528 8922 9656] │
│ [1449 7319 3939] [7350 9619 928] [7542 4704 1477] [ 980 6037 869] │
└└────────────────┘└────────────────┘└────────────────┘└────────────────┘┘
I would appreciate if you could review this code and let me know how I can improve it.
What I hope to see:
- possible mistakes or cases to break the code
- how to make it faster, more performant, pythonic
- how to extend it to higher dimensions
python numpy formatting ascii-art unicode
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Following this idea for pretty printing of numpy ndarrays, I have developed a very primitive prototype:
def ndtotext(A, w=None, h=None):
if A.ndim==1:
if w == None :
return str(A)
else:
s ='['+' '*(max(w[-1],len(str(A[0])))-len(str(A[0]))) +str(A[0])
for i,AA in enumerate(A[1:]):
s += ' '*(max(w[i],len(str(AA)))-len(str(AA))+1)+str(AA)
s +='] '
elif A.ndim==2:
w1 = [max([len(str(s)) for s in A[:,i]]) for i in range(A.shape[1])]
w0 = sum(w1)+len(w1)+1
s= u'u250c'+u'u2500'*w0+u'u2510' +'n'
for AA in A:
s += ' ' + ndtotext(AA, w=w1) +'n'
s += u'u2514'+u'u2500'*w0+u'u2518'
elif A.ndim==3:
h=A.shape[1]
s1=u'u250c' +'n' + (u'u2502'+'n')*h + u'u2514'+'n'
s2=u'u2510' +'n' + (u'u2502'+'n')*h + u'u2518'+'n'
strings=[ndtotext(a)+'n' for a in A]
strings.append(s2)
strings.insert(0,s1)
s='n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
return s
for example:
shape = 4, 5, 3
C=np.random.randint(10000, size=np.prod(shape)).reshape(shape)
print(ndtotext(C))
┌┌────────────────â”Â┌────────────────â”Â┌────────────────â”Â┌────────────────â”Ââ”Â
│ [9298 4404 1759] [5426 3488 9267] [8884 7721 579] [6872 4226 1858] │
│ [6723 271 8466] [9885 6760 8949] [ 295 7422 5659] [5322 4239 7446] │
│ [7156 6077 9390] [2712 6379 2832] [6956 626 5534] [ 142 4090 6390] │
│ [9377 9033 1953] [8986 3791 4538] [2466 8572 662] [1528 8922 9656] │
│ [1449 7319 3939] [7350 9619 928] [7542 4704 1477] [ 980 6037 869] │
└└────────────────┘└────────────────┘└────────────────┘└────────────────┘┘
I would appreciate if you could review this code and let me know how I can improve it.
What I hope to see:
- possible mistakes or cases to break the code
- how to make it faster, more performant, pythonic
- how to extend it to higher dimensions
python numpy formatting ascii-art unicode
python numpy formatting ascii-art unicode
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
edited 1 hour ago
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 2 hours ago


Foad
1313
1313
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Foad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1
How many dimensions does this work with? 1-3.
– Peilonrayz
2 hours ago
@Peilonrayz this one works 1-3 but the HTML version developed by others might work for further dimensions too. I haven't checked. It would be great if we could extend this to all dimensions. I guess doing some text/string work plus recursion this should be doable.
– Foad
2 hours ago
1
Can you modify your example to actually include how to call your function? I.e. what shouldw
look like?
– Graipher
1 hour ago
1
@Foad: Well, it is mostly trivial, but for the 1D case it is not so clear to me what and if anything should be passed forw
.
– Graipher
1 hour ago
1
@Graipher my apologies. yeah the w thing is very badly implemented. I'm actually very embarrassed by it. please help me know how if you can think of a better approach.
– Foad
1 hour ago
 |Â
show 1 more comment
1
How many dimensions does this work with? 1-3.
– Peilonrayz
2 hours ago
@Peilonrayz this one works 1-3 but the HTML version developed by others might work for further dimensions too. I haven't checked. It would be great if we could extend this to all dimensions. I guess doing some text/string work plus recursion this should be doable.
– Foad
2 hours ago
1
Can you modify your example to actually include how to call your function? I.e. what shouldw
look like?
– Graipher
1 hour ago
1
@Foad: Well, it is mostly trivial, but for the 1D case it is not so clear to me what and if anything should be passed forw
.
– Graipher
1 hour ago
1
@Graipher my apologies. yeah the w thing is very badly implemented. I'm actually very embarrassed by it. please help me know how if you can think of a better approach.
– Foad
1 hour ago
1
1
How many dimensions does this work with? 1-3.
– Peilonrayz
2 hours ago
How many dimensions does this work with? 1-3.
– Peilonrayz
2 hours ago
@Peilonrayz this one works 1-3 but the HTML version developed by others might work for further dimensions too. I haven't checked. It would be great if we could extend this to all dimensions. I guess doing some text/string work plus recursion this should be doable.
– Foad
2 hours ago
@Peilonrayz this one works 1-3 but the HTML version developed by others might work for further dimensions too. I haven't checked. It would be great if we could extend this to all dimensions. I guess doing some text/string work plus recursion this should be doable.
– Foad
2 hours ago
1
1
Can you modify your example to actually include how to call your function? I.e. what should
w
look like?– Graipher
1 hour ago
Can you modify your example to actually include how to call your function? I.e. what should
w
look like?– Graipher
1 hour ago
1
1
@Foad: Well, it is mostly trivial, but for the 1D case it is not so clear to me what and if anything should be passed for
w
.– Graipher
1 hour ago
@Foad: Well, it is mostly trivial, but for the 1D case it is not so clear to me what and if anything should be passed for
w
.– Graipher
1 hour ago
1
1
@Graipher my apologies. yeah the w thing is very badly implemented. I'm actually very embarrassed by it. please help me know how if you can think of a better approach.
– Foad
1 hour ago
@Graipher my apologies. yeah the w thing is very badly implemented. I'm actually very embarrassed by it. please help me know how if you can think of a better approach.
– Foad
1 hour ago
 |Â
show 1 more comment
1 Answer
1
active
oldest
votes
up vote
2
down vote
If A.ndim
is not in 1, 2, 3
, your code tries to return a non-existing string s
. It would be better to be explicit about what your code supports atm:
def ndtotext(A, w=None, h=None):
...
else:
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
return s
While we are at the point of having your code be clear about what is happening, you should add a docstring
explaining what your code does:
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
...
Next, Python has an official style-guide, PEP8, which programmers are encouraged to follow. One of the things it recommends is surrounding operators with spaces (which I fixed in the rest of the code) and using lower_case
for variables and functions (which I left as is for now).
Now, let's come to your actual code:
- You calculate some values multiple times (like
str(A[0])
), save those to a variable. - If you want to compare to
None
, useis
(since it is a singleton). - No
else
needed after anif...return
(this is a matter of personal style, I prefer not having the additional level of indentation). - Use
str.rjust
to add enough whitespace in front of your strings. You could also usestr.format
for this, but it looks less nice. - Your
w
has a weird structure, with the width of the first column being the last entry and the rest starting at zero. - Give the unicode values names. And then add functions to draw a line of specified length.
String addition is costly and slow. Try to consistently use building a list and
str.join
ing it.UPPER_LEFT = u'u250c'
UPPER_RIGHT = u'u2510'
LOWER_LEFT = u'u2514'
LOWER_RIGHT = u'u2518'
HORIZONTAL = u'u2500'
VERTICAL = u'u2502'
def upper_line(width):
return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
if A.ndim == 1:
if w is None:
return str(A)
s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
return '[]'.format(s)
elif A.ndim == 2:
widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
s = "".join([' ' + ndtotext(AA, w=widths) + 'n' for AA in A])
w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
return upper_line(w0) + s + lower_line(w0)
elif A.ndim == 3:
h = A.shape[1]
strings = [left_line(h)]
strings.extend(ndtotext(a) + 'n' for a in A)
strings.append(right_line(h))
return 'n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
This can probably be even more compactified, but I think it is a good start.
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
If A.ndim
is not in 1, 2, 3
, your code tries to return a non-existing string s
. It would be better to be explicit about what your code supports atm:
def ndtotext(A, w=None, h=None):
...
else:
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
return s
While we are at the point of having your code be clear about what is happening, you should add a docstring
explaining what your code does:
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
...
Next, Python has an official style-guide, PEP8, which programmers are encouraged to follow. One of the things it recommends is surrounding operators with spaces (which I fixed in the rest of the code) and using lower_case
for variables and functions (which I left as is for now).
Now, let's come to your actual code:
- You calculate some values multiple times (like
str(A[0])
), save those to a variable. - If you want to compare to
None
, useis
(since it is a singleton). - No
else
needed after anif...return
(this is a matter of personal style, I prefer not having the additional level of indentation). - Use
str.rjust
to add enough whitespace in front of your strings. You could also usestr.format
for this, but it looks less nice. - Your
w
has a weird structure, with the width of the first column being the last entry and the rest starting at zero. - Give the unicode values names. And then add functions to draw a line of specified length.
String addition is costly and slow. Try to consistently use building a list and
str.join
ing it.UPPER_LEFT = u'u250c'
UPPER_RIGHT = u'u2510'
LOWER_LEFT = u'u2514'
LOWER_RIGHT = u'u2518'
HORIZONTAL = u'u2500'
VERTICAL = u'u2502'
def upper_line(width):
return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
if A.ndim == 1:
if w is None:
return str(A)
s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
return '[]'.format(s)
elif A.ndim == 2:
widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
s = "".join([' ' + ndtotext(AA, w=widths) + 'n' for AA in A])
w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
return upper_line(w0) + s + lower_line(w0)
elif A.ndim == 3:
h = A.shape[1]
strings = [left_line(h)]
strings.extend(ndtotext(a) + 'n' for a in A)
strings.append(right_line(h))
return 'n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
This can probably be even more compactified, but I think it is a good start.
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
add a comment |Â
up vote
2
down vote
If A.ndim
is not in 1, 2, 3
, your code tries to return a non-existing string s
. It would be better to be explicit about what your code supports atm:
def ndtotext(A, w=None, h=None):
...
else:
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
return s
While we are at the point of having your code be clear about what is happening, you should add a docstring
explaining what your code does:
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
...
Next, Python has an official style-guide, PEP8, which programmers are encouraged to follow. One of the things it recommends is surrounding operators with spaces (which I fixed in the rest of the code) and using lower_case
for variables and functions (which I left as is for now).
Now, let's come to your actual code:
- You calculate some values multiple times (like
str(A[0])
), save those to a variable. - If you want to compare to
None
, useis
(since it is a singleton). - No
else
needed after anif...return
(this is a matter of personal style, I prefer not having the additional level of indentation). - Use
str.rjust
to add enough whitespace in front of your strings. You could also usestr.format
for this, but it looks less nice. - Your
w
has a weird structure, with the width of the first column being the last entry and the rest starting at zero. - Give the unicode values names. And then add functions to draw a line of specified length.
String addition is costly and slow. Try to consistently use building a list and
str.join
ing it.UPPER_LEFT = u'u250c'
UPPER_RIGHT = u'u2510'
LOWER_LEFT = u'u2514'
LOWER_RIGHT = u'u2518'
HORIZONTAL = u'u2500'
VERTICAL = u'u2502'
def upper_line(width):
return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
if A.ndim == 1:
if w is None:
return str(A)
s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
return '[]'.format(s)
elif A.ndim == 2:
widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
s = "".join([' ' + ndtotext(AA, w=widths) + 'n' for AA in A])
w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
return upper_line(w0) + s + lower_line(w0)
elif A.ndim == 3:
h = A.shape[1]
strings = [left_line(h)]
strings.extend(ndtotext(a) + 'n' for a in A)
strings.append(right_line(h))
return 'n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
This can probably be even more compactified, but I think it is a good start.
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
add a comment |Â
up vote
2
down vote
up vote
2
down vote
If A.ndim
is not in 1, 2, 3
, your code tries to return a non-existing string s
. It would be better to be explicit about what your code supports atm:
def ndtotext(A, w=None, h=None):
...
else:
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
return s
While we are at the point of having your code be clear about what is happening, you should add a docstring
explaining what your code does:
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
...
Next, Python has an official style-guide, PEP8, which programmers are encouraged to follow. One of the things it recommends is surrounding operators with spaces (which I fixed in the rest of the code) and using lower_case
for variables and functions (which I left as is for now).
Now, let's come to your actual code:
- You calculate some values multiple times (like
str(A[0])
), save those to a variable. - If you want to compare to
None
, useis
(since it is a singleton). - No
else
needed after anif...return
(this is a matter of personal style, I prefer not having the additional level of indentation). - Use
str.rjust
to add enough whitespace in front of your strings. You could also usestr.format
for this, but it looks less nice. - Your
w
has a weird structure, with the width of the first column being the last entry and the rest starting at zero. - Give the unicode values names. And then add functions to draw a line of specified length.
String addition is costly and slow. Try to consistently use building a list and
str.join
ing it.UPPER_LEFT = u'u250c'
UPPER_RIGHT = u'u2510'
LOWER_LEFT = u'u2514'
LOWER_RIGHT = u'u2518'
HORIZONTAL = u'u2500'
VERTICAL = u'u2502'
def upper_line(width):
return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
if A.ndim == 1:
if w is None:
return str(A)
s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
return '[]'.format(s)
elif A.ndim == 2:
widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
s = "".join([' ' + ndtotext(AA, w=widths) + 'n' for AA in A])
w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
return upper_line(w0) + s + lower_line(w0)
elif A.ndim == 3:
h = A.shape[1]
strings = [left_line(h)]
strings.extend(ndtotext(a) + 'n' for a in A)
strings.append(right_line(h))
return 'n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
This can probably be even more compactified, but I think it is a good start.
If A.ndim
is not in 1, 2, 3
, your code tries to return a non-existing string s
. It would be better to be explicit about what your code supports atm:
def ndtotext(A, w=None, h=None):
...
else:
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
return s
While we are at the point of having your code be clear about what is happening, you should add a docstring
explaining what your code does:
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
...
Next, Python has an official style-guide, PEP8, which programmers are encouraged to follow. One of the things it recommends is surrounding operators with spaces (which I fixed in the rest of the code) and using lower_case
for variables and functions (which I left as is for now).
Now, let's come to your actual code:
- You calculate some values multiple times (like
str(A[0])
), save those to a variable. - If you want to compare to
None
, useis
(since it is a singleton). - No
else
needed after anif...return
(this is a matter of personal style, I prefer not having the additional level of indentation). - Use
str.rjust
to add enough whitespace in front of your strings. You could also usestr.format
for this, but it looks less nice. - Your
w
has a weird structure, with the width of the first column being the last entry and the rest starting at zero. - Give the unicode values names. And then add functions to draw a line of specified length.
String addition is costly and slow. Try to consistently use building a list and
str.join
ing it.UPPER_LEFT = u'u250c'
UPPER_RIGHT = u'u2510'
LOWER_LEFT = u'u2514'
LOWER_RIGHT = u'u2518'
HORIZONTAL = u'u2500'
VERTICAL = u'u2502'
def upper_line(width):
return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
def ndtotext(A, w=None, h=None):
"""Returns a string to pretty print the numpy.ndarray `A`.
Currently supports 1 - 3 dimensions only.
Raises a NotImplementedError if an array with more dimensions is passed.
Describe `w` and `h`.
"""
if A.ndim == 1:
if w is None:
return str(A)
s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
return '[]'.format(s)
elif A.ndim == 2:
widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
s = "".join([' ' + ndtotext(AA, w=widths) + 'n' for AA in A])
w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
return upper_line(w0) + s + lower_line(w0)
elif A.ndim == 3:
h = A.shape[1]
strings = [left_line(h)]
strings.extend(ndtotext(a) + 'n' for a in A)
strings.append(right_line(h))
return 'n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
This can probably be even more compactified, but I think it is a good start.
edited 42 mins ago
answered 47 mins ago
Graipher
21.7k53183
21.7k53183
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
add a comment |Â
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
– Foad
6 mins ago
add a comment |Â
Foad is a new contributor. Be nice, and check out our Code of Conduct.
Foad is a new contributor. Be nice, and check out our Code of Conduct.
Foad is a new contributor. Be nice, and check out our Code of Conduct.
Foad is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207139%2fpretty-printing-of-the-numpy-ndarrays%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
How many dimensions does this work with? 1-3.
– Peilonrayz
2 hours ago
@Peilonrayz this one works 1-3 but the HTML version developed by others might work for further dimensions too. I haven't checked. It would be great if we could extend this to all dimensions. I guess doing some text/string work plus recursion this should be doable.
– Foad
2 hours ago
1
Can you modify your example to actually include how to call your function? I.e. what should
w
look like?– Graipher
1 hour ago
1
@Foad: Well, it is mostly trivial, but for the 1D case it is not so clear to me what and if anything should be passed for
w
.– Graipher
1 hour ago
1
@Graipher my apologies. yeah the w thing is very badly implemented. I'm actually very embarrassed by it. please help me know how if you can think of a better approach.
– Foad
1 hour ago