Pretty printing of the numpy ndarrays Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern) Announcing the arrival of Valued Associate #679: Cesar Manara Unicorn Meta Zoo #1: Why another podcast?Compound assignment operators in Python's NumPy libraryOptimizing numpy gmean calculationEfficient numpy cosine distance calculationPretty printing degrees input to radiansPrinting binary treesMeasuring the distance between NumPy matrixesPretty print a 2D matrix in C (numpy style)JSON pretty printPretty-printed tables in HaskellPretty print a tree
New Order #6: Easter Egg
Understanding piped commands in GNU/Linux
Random body shuffle every night—can we still function?
How to get a flat-head nail out of a piece of wood?
IC on Digikey is 5x more expensive than board containing same IC on Alibaba: How?
How to resize main filesystem
Can I take recommendation from someone I met at a conference?
How can I introduce the names of fantasy creatures to the reader?
Is honorific speech ever used in the first person?
Is there a spell that can create a permanent fire?
How can I list files in reverse time order by a command and pass them as arguments to another command?
Is it OK if I do not take the receipt in Germany?
How to create a button that adds InputFields when clicked?
Can a Knight grant Knighthood to another?
By what mechanism was the 2017 UK General Election called?
What helicopter has the most rotor blades?
How do I say "this must not happen"?
.bashrc alias for a command with fixed second parameter
Table formatting with tabularx?
The test team as an enemy of development? And how can this be avoided?
What should one know about term logic before studying propositional and predicate logic?
Is the Mordenkainen's Sword spell underpowered?
draw a pulley system
Can I cut the hair of a conjured korred with a blade made of precious material to harvest that material from the korred?
Pretty printing of the numpy ndarrays
Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)
Announcing the arrival of Valued Associate #679: Cesar Manara
Unicorn Meta Zoo #1: Why another podcast?Compound assignment operators in Python's NumPy libraryOptimizing numpy gmean calculationEfficient numpy cosine distance calculationPretty printing degrees input to radiansPrinting binary treesMeasuring the distance between NumPy matrixesPretty print a 2D matrix in C (numpy style)JSON pretty printPretty-printed tables in HaskellPretty print a tree
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
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
P.S. For those who follow up this idea I have integrated everythin here in this Jupyter Notebook
python numpy formatting ascii-art unicode
$endgroup$
|
show 1 more comment
$begingroup$
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
P.S. For those who follow up this idea I have integrated everythin here in this Jupyter Notebook
python numpy formatting ascii-art unicode
$endgroup$
1
$begingroup$
How many dimensions does this work with? 1-3.
$endgroup$
– Peilonrayz
Nov 7 '18 at 13:26
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 13:29
1
$begingroup$
Can you modify your example to actually include how to call your function? I.e. what shouldw
look like?
$endgroup$
– Graipher
Nov 7 '18 at 13:56
1
$begingroup$
@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
.
$endgroup$
– Graipher
Nov 7 '18 at 14:02
1
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 14:05
|
show 1 more comment
$begingroup$
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
P.S. For those who follow up this idea I have integrated everythin here in this Jupyter Notebook
python numpy formatting ascii-art unicode
$endgroup$
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
P.S. For those who follow up this idea I have integrated everythin here in this Jupyter Notebook
python numpy formatting ascii-art unicode
python numpy formatting ascii-art unicode
edited 6 mins ago
Foad
asked Nov 7 '18 at 13:23
FoadFoad
1665
1665
1
$begingroup$
How many dimensions does this work with? 1-3.
$endgroup$
– Peilonrayz
Nov 7 '18 at 13:26
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 13:29
1
$begingroup$
Can you modify your example to actually include how to call your function? I.e. what shouldw
look like?
$endgroup$
– Graipher
Nov 7 '18 at 13:56
1
$begingroup$
@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
.
$endgroup$
– Graipher
Nov 7 '18 at 14:02
1
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 14:05
|
show 1 more comment
1
$begingroup$
How many dimensions does this work with? 1-3.
$endgroup$
– Peilonrayz
Nov 7 '18 at 13:26
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 13:29
1
$begingroup$
Can you modify your example to actually include how to call your function? I.e. what shouldw
look like?
$endgroup$
– Graipher
Nov 7 '18 at 13:56
1
$begingroup$
@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
.
$endgroup$
– Graipher
Nov 7 '18 at 14:02
1
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 14:05
1
1
$begingroup$
How many dimensions does this work with? 1-3.
$endgroup$
– Peilonrayz
Nov 7 '18 at 13:26
$begingroup$
How many dimensions does this work with? 1-3.
$endgroup$
– Peilonrayz
Nov 7 '18 at 13:26
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 13:29
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 13:29
1
1
$begingroup$
Can you modify your example to actually include how to call your function? I.e. what should
w
look like?$endgroup$
– Graipher
Nov 7 '18 at 13:56
$begingroup$
Can you modify your example to actually include how to call your function? I.e. what should
w
look like?$endgroup$
– Graipher
Nov 7 '18 at 13:56
1
1
$begingroup$
@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
.$endgroup$
– Graipher
Nov 7 '18 at 14:02
$begingroup$
@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
.$endgroup$
– Graipher
Nov 7 '18 at 14:02
1
1
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 14:05
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 14:05
|
show 1 more comment
1 Answer
1
active
oldest
votes
$begingroup$
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 + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * width + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * height + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * height + [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) + 'n' + 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.
Example usage:
x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
[0 1 2 3]
[4 5 6 7]
[8 9 10 11]
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
$endgroup$
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
1
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
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 + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * width + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * height + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * height + [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) + 'n' + 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.
Example usage:
x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
[0 1 2 3]
[4 5 6 7]
[8 9 10 11]
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
$endgroup$
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
1
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
add a comment |
$begingroup$
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 + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * width + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * height + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * height + [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) + 'n' + 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.
Example usage:
x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
[0 1 2 3]
[4 5 6 7]
[8 9 10 11]
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
$endgroup$
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
1
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
add a comment |
$begingroup$
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 + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * width + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * height + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * height + [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) + 'n' + 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.
Example usage:
x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
[0 1 2 3]
[4 5 6 7]
[8 9 10 11]
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
$endgroup$
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 + UPPER_RIGHT
def lower_line(width):
return LOWER_LEFT + HORIZONTAL * width + LOWER_RIGHT
def left_line(height):
return "n".join([UPPER_LEFT] + [VERTICAL] * height + [LOWER_LEFT])
def right_line(height):
return "n".join([UPPER_RIGHT] + [VERTICAL] * height + [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) + 'n' + 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.
Example usage:
x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
[0 1 2 3]
[4 5 6 7]
[8 9 10 11]
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
edited Nov 11 '18 at 13:02
answered Nov 7 '18 at 14:55
GraipherGraipher
27.6k54499
27.6k54499
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
1
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
add a comment |
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
1
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
wow. awesome. thanks a lot. I'm gonna try your points and get back here.
$endgroup$
– Foad
Nov 7 '18 at 15:36
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
$begingroup$
You code does not work properly. I edited it so it works but for some reason my edit was rejected!
$endgroup$
– Foad
Nov 10 '18 at 18:19
1
1
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
@Foad: You are right, fixed it and added examples.
$endgroup$
– Graipher
Nov 11 '18 at 13:02
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
$begingroup$
I'm integrating all the results, including your suggestions here in this Notebook.
$endgroup$
– Foad
Nov 12 '18 at 10:41
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
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
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
$begingroup$
How many dimensions does this work with? 1-3.
$endgroup$
– Peilonrayz
Nov 7 '18 at 13:26
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 13:29
1
$begingroup$
Can you modify your example to actually include how to call your function? I.e. what should
w
look like?$endgroup$
– Graipher
Nov 7 '18 at 13:56
1
$begingroup$
@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
.$endgroup$
– Graipher
Nov 7 '18 at 14:02
1
$begingroup$
@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.
$endgroup$
– Foad
Nov 7 '18 at 14:05