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;








13












$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










share|improve this question











$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 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

















13












$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










share|improve this question











$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 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













13












13








13


3



$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










share|improve this question











$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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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












  • 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







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










1 Answer
1






active

oldest

votes


















5












$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, use is (since it is a singleton).

  • No else needed after an if...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 use str.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.joining 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] │
└└─────┘└─────┘└───────┘┘





share|improve this answer











$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











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
);



);













draft saved

draft discarded


















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









5












$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, use is (since it is a singleton).

  • No else needed after an if...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 use str.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.joining 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] │
└└─────┘└─────┘└───────┘┘





share|improve this answer











$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















5












$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, use is (since it is a singleton).

  • No else needed after an if...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 use str.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.joining 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] │
└└─────┘└─────┘└───────┘┘





share|improve this answer











$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













5












5








5





$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, use is (since it is a singleton).

  • No else needed after an if...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 use str.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.joining 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] │
└└─────┘└─────┘└───────┘┘





share|improve this answer











$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, use is (since it is a singleton).

  • No else needed after an if...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 use str.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.joining 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] │
└└─────┘└─────┘└───────┘┘






share|improve this answer














share|improve this answer



share|improve this answer








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
















  • $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

















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar