How do I align text output in Python?

Question:

I’ve got a function which creates a little star table based on some data collected elsewhere in the program. While the table produces the correct output, since the number of characters in each number changes, it un-aligns the table. For example,

70-78: *****
79-87: ***
88-96: ****
97-105: **
106-114: ******
115-123: ****

Is there any way to align the stars so that the output is something like this:

70-78:   *****
79-87:   ***
88-96:   ****
97-105:  **
106-114: ******
115-123: ****

Here’s how I currently print the table.

for x in range(numClasses):
    print('{0}-{1}: {2}'.format(lower[x],upper[x],"*"*num[x]))
Asked By: CopOnTheRun

||

Answers:

This should do the trick. I assume there are clever ways.

print '70-78:'.ljust(10) + '*****'

You could also use expandtabs()

print ('70-78'+'t'+ '*****').expandtabs(10)
Answered By: Next Door Engineer

Easy way (in your case) would be to put a tab instead of space:

for x in range(numClasses):
    print('{0}-{1}:t{2}'.format(lower[x],upper[x],"*"*num[x]))

Another way would be to use str.ljust:

for x in range(numClasses):
    label = '{0}-{1}:'.format(lower[x], upper[x])
    print(label.ljust(10, ' ') + "*" * num[x])
Answered By: Jacek Przemieniecki
lower = [70, 79, 88, 97, 106]
upper = [78, 87, 105, 114, 123]
num = [5, 3, 4, 2, 6, 4]

for l, u, n in zip(lower, upper, num):
    print('{0:<9} {1}'.format('{0}-{1}:'.format(l, u), '*' * n))

http://docs.python.org/3/library/string.html#format-specification-mini-language

Answered By: falsetru

Ok, while the solution I’m using is admittedly ad-hoc, it works, and scales better than the answers so far. Basically it’s just the method VR17 suggested, but with a little more so that the tab size scales with the data set, and isn’t just hard coded in.

First I made a method that returns the number characters in some number.

def charNum(number):
    return math.floor(math.log(number,10)+1)

Then I used the charNum() function on the last point of my lower and upper data sets. Only the last point had to be used on each list because the last point is the biggest number. I then counted the character that weren’t numbers(the dash, semicolon, and space), and adjusted accordingly.
So the final tabLength variable looks like this:

tabLength = charNum(lower[-1])+charNum(upper[-1])+3

I then plugged the tabLength variable into the expandTab() function to get proper spacing. Here’s some example output:

1-11:  *******
12-22: *
23-33: ***
34-44: **
45-55: ***
56-66: *

99-249:   *****
250-400:  ****
401-551:  **
552-702:  **
703-853:  *
854-1004: ***

99-200079:      ******
200080-400060:  **
400061-600041:  ****
600042-800022:  **
800023-1000003: *

The only problem I can really see with this is that if I wanted to expand this to a table or something the tabs would be all funky. If I did that though, I’d probably look into ljust and rjustwhich I’m not all that familiar with right now. I’ll leave the question open for a little while in case someone comes up with a better answer.

Answered By: CopOnTheRun

str.format already has the possibility to specify alignment. You can do that using {0:>5}; this would align parameter 0 to the right for 5 characters. We can then dynamically build a format string using the maximum number of digits necessary to display all numbers equally:

>>> lower = [70, 79, 88, 97, 106, 115]
>>> upper = [78, 87, 96, 105, 114, 123]
>>> num = [5, 3, 4, 2, 6, 4]
>>> digits = len(str(max(lower + upper)))
>>> digits
3
>>> f = '{0:>%d}-{1:>%d}: {2}' % (digits, digits)
>>> f
'{0:>3}-{1:>3}: {2}'
>>> for i in range(len(num)):
        print(f.format(lower[i], upper[i], '*' * num[i]))

 70- 78: *****
 79- 87: ***
 88- 96: ****
 97-105: **
106-114: ******
115-123: ****

Actually, you could even use a single format string here with nested fields:

>>> for i in range(len(num)):
        print('{0:>{numLength}}-{1:>{numLength}}: {2}'.format(lower[i], upper[i], '*' * num[i], numLength=digits))
Answered By: poke
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.