Trying to format a string into columns with python - python

I am trying to format a string to display two columns for a high score table. Python is able to do this well when using print
print '{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x)
but when trying to use a formatted string, but becomes more challenging it seems. This is the result I am trying to get:
#for name, score in list: prints the following
1. FirstName LastName 45000
2. First LastName 78000
3. Fst Lst 11123
4. Name Name 40404
5. llll lll 12345
This is all one string that goes into a pygtk label. Currently I have this:
score_string += "%i. %-15.12s\t%15s\n" % (index, name, score)
which yields untrustworthy results. My current test data is displayed as the following:
1. Firstname Lastname 49900
2. First Last 93000
3. Name Name 6400
Because the first name in that list is longer than the rest (in width, not count of characters) the tab forces the score out of position. Is there a way to do this that not only takes the length of the string, but the width of the string into account as well?

Is something like this acceptable?
>>> names = ["Firstname Lastname", "First Last", "Name Name"]
>>> scores = [49900, 93000, 6400]
>>> for i,v in enumerate(zip(names, scores)):
... name, score = v[0], v[1]
... print "% *d. % -*s %d" % (3, i, 30, name, score)
...
0. Firstname Lastname 49900
1. First Last 93000
2. Name Name 6400
Here the "name" field is padded with spaces to a max width of 30 characters.
Edit: I now see that the width of the font is also a problem. I did not realize that at first from your question. I'll leave this up in case future Googlers end up here for a different reason.

You have two options:
Change the font of the PyGTK label to a font that has equal width characters (not unreasonable in a game, it reminds us of the old arcade days). You can do this with set_markup of pango.Layout.
Use two labels next to each other and use the method set_alignment of the class pango.Layout. The first label aligns the name to the left, the second label contains the score and it aligns to the right. As long as their is enough space the names and scores will align nicely to the left and right respectively.

Related

String Formatting Dollar Sign In Python

So I'm trying to get the dollar sign to appear directly to the left of the digits under the column 'Cost'. I'm having trouble figuring this out and any help is appreciated.
# Question 5
print("\nQuestion 5.")
# Get amount of each type of ticket to be purchased
adultTickets = input("\nHow many adult tickets you want to order: ")
adultCost = int(adultTickets) * 50.5
childTickets = input("How many children (>=10 years old) tickets: ")
childCost = int(childTickets) * 10.5
youngChildTickets = input("How many children (<10 years old) tickets: ")
# Display ticket info
print ("\n{0:<17} {1:>17} {2:>12}".format("Type", "Number of tickets",
"Cost"))
print ("{0:<17} {1:>17}${2:>12.2f}".format("Adult", adultTickets, adultCost))
print ("{0:<17} {1:>17}${2:>12.2f}".format("Children (>=10)", childTickets,
childCost))
print ("{0:<17} {1:>17} {2:>12}".format("Children (<10)", youngChildTickets,
"free"))
#Calculate total cost and total amount of tickets
totalTickets = (int(adultTickets) + int(childTickets) +
int(youngChildTickets))
totalCost = adultCost + childCost
print ("{0:<17} {1:>17}${2:>12.2f}".format("Total", totalTickets, totalCost))
I also want the cost column to be formatted right, which for some reason it isn't when I run the program.
(My output):
Edit: I also can't format the '$' onto the cost, as I have to keep the 2 decimal places in the formatting
If I understand correctly, you want to format a floating point number into a string, and have a dollar sign appear in the output in between the number and the padding that you use to space it out in the string. For example, you want to be able to create these two strings with the same formatting code (just different values):
foo: $1.23
foo: $12.34
Unfortunately, you can't do this with just one string formatting operation. When you apply padding to a number, the padding characters will appear in between the number and any prefixing text, like the dollar signs in your current code. You probably need to format the number in two steps. First make the numbers into strings prefixed with the dollar signs, then format again to insert the dollar strings into the final string with the appropriate padding.
Here's how I'd produce the example strings above:
a = 1.23
b = 12.34
a_dollars = "${:.2f}".format(a) # make strings with leading dollar sign
b_dollars = "${:.2f}".format(b)
a_padded = "foo:{:>8}".format(a_dollars) # insert them into strings with padding
b_padded = "foo:{:>8}".format(b_dollars)
I had the same issue, and I was able to solve it with a string like this:
print("%5d" % month,"%3s"%'$',"%12.2f" % balance,"%4s"%'$',"%11.2f" % interest,"%4s"%'$',"%13.2f" % principal)
It printed this in a nice even table.
Month | Current Balance | Interest Owned | Principal Owned
1 $ 9000.00 $ 90.00 $ 360.00
This indented the $ to the start of each table column, while also leaving enough space for very large figures. It's not ideal though since it would be nice to nest it right next to the dollar number.

is there a way to modify a string to remove a decimal?

I have a file with a lot of images. Each image is named something like:
100304.jpg
100305.jpg
100306.jpg
etc...
I also have a spreadsheet, Each image is a row, the first value in the row is the name, the values after the name are various decimals and 0's to describe features of each image.
The issue is that when I pull the name from the sheet, something is adding a decimal which then results in the file not being able to be transferred via the shutil.move()
import xlrd
import shutil
dataLocation = "C:/Users/User/Documents/Python/Project/sort_solutions_rev1.xlsx"
imageLocBase = "C:/Users/User/Documents/Python/Project/unsorted"
print("Specify which folder to put images in. Type the number only.")
print("1")
print("2")
print("3")
int(typeOfSet) = input("")
#Sorting for folder 1
if int(typeOfSet) == 1:
#Identifying what to move
name = str(sheet.cell(int(nameRow), 0).value)
sortDataStorage = (sheet.cell(int(nameRow), 8).value) #float
sortDataStorageNoFloat = str(sortDataStorage) #non-float
print("Proccessing: " + name)
print(name + " has a correlation of " + (sortDataStorageNoFloat))
#sorting for this folder utilizes the information in column 8)
if sortDataStorage >= sortAc:
print("test success")
folderPath = "C:/Users/User/Documents/Python/Project/Image Folder/Folder1"
shutil.move(imageLocBase + "/" + name, folderPath)
print(name + " has been sorted.")
else:
print(name + " does not meet correlation requirement. Moving to next image.")
The issue I'm having occurs with the shutil.move(imageLocBase + "/" +name, folderPath)
For some reason my code takes the name from the spreadsheet (ex: 100304) and then adds a ".0" So when trying to move a file, it is trying to move 100304.0 (which doesn't exist) instead of 100304.
Using pandas to read your Excel file.
As suggested in a comment on the original question, here is a quick example of how to use pandas to read your Excel file, along with an example of the data structure.
Any questions, feel free to shout, or have a look into the docs.
import pandas as pd
# My path looks a little different as I'm on Linux.
path = '~/Desktop/so/MyImages.xlsx'
df = pd.read_excel(path)
Data Structure
This is completely contrived as I don't have an example of your actual file.
IMAGE_NAME FEATURE_1 FEATURE_2 FEATURE_3
0 100304.jpg 0.0111 0.111 1.111
1 100305.jpg 0.0222 0.222 2.222
2 100306.jpg 0.0333 0.333 3.333
Hope this helps get you started.
Suggestion:
Excel likes to think it's clever and does 'unexpected' things, as you're experiencing with the decimal (data type) issue. Perhaps consider storing your image data in a database (SQLite) or as plain old CSV file. Pandas can read from either of these as well! :-)
splitOn = '.'
nameOfFile = text.split(splitOn, 1)[0]
Should work
if we take your file name eg 12345.0 and create a var
name = "12345.0"
Now we need to split this var. In this case we wish to split on .
So we save this condition as a second var
splitOn = '.'
Using the .split for python.
Here we offer the text (variable name) and the python split command.
so to make it literal
12345.0
split at .
only make one split and save as two vars in a list
(so we have 12345 at position 0 (1st value)
and 0 at position 1 (2nd value) in a list)
save 1st var
(as all lists are 0 based we ask for [0]
(if you ever get confused with list, arrays etc just start counting
from 0 instead of one on your hands and then you know
ie position 0 1 2 3 4 = 1st value, 2nd value, 3rd value, 4th value, 5th value)
nameOfFile = name.split(splitOn, 1)[0]
12345.0 split ( split on . , only one split ) save position 0 ie first value
So.....
name = 12345.0
splitOn = '.'
nameOfFile = name.split(splitOn, 1)[0]
yield(nameOfFile)
output will be
12345
I hope that helps
https://www.geeksforgeeks.org/python-string-split/
OR
as highlighted below, convert to float to in
https://www.geeksforgeeks.org/type-conversion-python/
if saved as float
name 12345.0
newName = round(int(name))
this will round the float (as its 0 will round down)
OR
if float is saved as a string
print(int(float(name)))
Apparently the value you retrieve from the spreadsheet comes parsed as a float, so when you cast it to string it retains the decimal part.
You can trim the “.0” from the string value, or cast it to integer before casting to string.
You could also check the spreadsheet’s cell format and ensure it is set to normal (idk the setting, but something that is not a number). With that fixed, your data probably wont come with the .0 anymore.
If always add ".0" to the end of the variable, You need to read the var_string "name" in this way:
shutil.move(imageLocBase + "/" + name[:-2], folderPath)
A string is like a list that we can choose the elements to read.
Slicing is colled this method
Sorry for my English. Bye
All these people have taken time to reply, please out of politeness rate the replies.

Function takes exactly 3 arguments (1 given)? Help formatting print statement

Here are my questions:
Create a function called "numSchools" that counts the schools of a specific type. The function should have three input parameters, (1) a string for the workspace, (2) a string for the shapefile name, and (3) a string for the facility type (e.g. "HIGH SCHOOL"), and one output parameter, (1) an integer for the number of schools of that facility type in the shapefile.
import arcpy
shapefile = "Schools.shp"
work = r"c:\Scripts\Lab 6 Data"
sTyp = "HIGH SCHOOL"
def numSchools(work, shapefile, sTyp):
whereClause = "\"FACILITY\" = 'HIGH SCHOOL' " # where clause for high schools
field = ['FACILITY']
searchCurs = arcpy.SearchCursor(shapefile, field, whereClause)
row = searchCurs.next()
for row in searchCurs:
# using getValue() to get the name of the high school
value = row.getValue("NAME")
high_schools = [row[0] for row in arcpy.SearchCursor(shapefile, field, whereClause)]
count = arcpy.GetCount_management(high_schools)
return count
numSchools(work, shapefile, sTyp)
print ("There are a total of: "),count
So this is my code that runs perfectly, but it is accomplished by scripting. I need to wrap it into a python function. (MY WEAKNESS). It seems there are some problems with the last line of my code. `
I am not quite sure how to format this last line of code to read
(there are a total of 29 high schools) while including necessary arguments.
You need to explicitly pass the arguments.
count = numSchools(work, shapefile, sTyp)
print("There are a total of: ", count)

Python write to a text file after certain column

I am using the following code:
f.write(str(foo) + ' ' + str(bar) + '\n')
The problem is that the number of letters in foo is different for each value and I get the following output:
Account Category DORMANT
Last Made Update 21/12/2013
Mortgages Partly Satisfied 0
The problem is that because I am using same amount of space (' ') for all the values and Mortgages Partly Satisfied is longer string, so the value 0 goes to the right. What I would like the output to be is:
Account Category DORMANT
Last Made Update 21/12/2013
Mortgages Partly Satisfied 0
My question is: Is there a way to insert the second value bar after certain amount of columns so the values will always be aligned?
I hope I was clear enough.
It's probably best to use string formatting with the str.format method, like so:
items = [
('Account Category', 'DORMANT'),
('Last Made Update', '21/12/2013'),
('Mortgages Partly Satisfied', '0'),
]
for label, value in items:
f.write('{:28} {}\n'.format(label, value))
The :28 is the width specifier. See format string docs for more info.
Python lets you add padding for strings by specifying the number of characters a given field should use. This can be used when writing to your file as follows:
data = [["Account Category", "DORMANT"], ["Last Made Update", "21/12/2013"], ["Mortgages Partly Satisfied", "0"]]
with open('output.txt', 'w') as f:
for v1, v2 in data:
f.write("{:28} {}\n".format(v1, v2))
Giving you:
Account Category DORMANT
Last Made Update 21/12/2013
Mortgages Partly Satisfied 0
You can use the ljust function, that returns the string left justified.
Just, try it:
f.write(str(foo).ljust(40) + str(bar) + '\n')
You can also check other methods in the docs
This is going to give you the next output:
Last Made Update 21/12/2013
Account Category DORMANT
Mortgages Partly Satisfied 0

How to call in a specifc csv field value in python

I am so new to python (a week in) so I hope I ask this question properly.
I have imported a grade sheet in csv format into python 2.7. The first column is the name of the student and the column titles are the name of the assignments. So the data looks something like this:
Name Test1 Test2 Test3
Robin 89 78 100
...
Rick 72 100 98
I want to be able to do (or have someone else do) 3 things just by typing in the name of the person and the assignment.
1. Get the score for that person for that assignment
2. Get the average score for that assignment
3. Get that persons average score
But for some reason I get lost at figuring how to get python to recognize the field I am trying to call in. So far this is what I have (so far the only part that works is calling in file):
data = csv.DictReader(open("C:\file.csv"))
for row in data:
print row
def grade()
student= input ("Enter a student name: ")
assignment= input("Enter a assignment: ")
for row in data:
task_grade= data.get(int(row["student"], int(row["assignment"])) # specific grade
task_total= sum(int(row['assignment'])) #assignment total
student_total= #student assignments total-- no clue how to do this
task_average= task_total/11
average_score= student_total/9
You can access the individual "columns" of your csv this way:
import csv
def parse_csv():
csv_file = open('data.csv', 'r')
r = csv.reader(csv_file)
grade_averages = {}
for row in r:
if row[0].startswith('Name'):
continue
#print "Student: ", row[0]
grades = []
for column in row[1:]:
#print "Grade: ", column
grades.append(int(column.strip()))
grade_total = 0
for i in grades:
grade_total += i
grade_averages[row[0]] = grade_total / len(grades)
#print "grade_averages: ", grade_averages
return grade_averages
def get_grade(student_name):
grade_averages = parse_csv()
return grade_averages[student_name]
print "Rick: ", get_grade('Rick')
print "Robin: ", get_grade('Robin')
What you are trying to do is not meant for Python because you have keys and values. However...
If you know that your columns are always the same, no need to use keywords, you can use positions:
Here is the easy, inefficient* way to do 1 and 3:
students_name = ...
number = ...
for line in open("C:\file.csv")).readlines()
items = line.split()
num_assignments = len(items)-1
name = items[0]
if name = students_name:
print("assignment score: {0}".format(items[number]))
asum = 0
for k in range(0,num_assignments):
asum+= items[k+1]
print("their average: {0}".format(asum / num_assignments)
To do 2, you should precompute the averages and return them beucase the averages for each assignment is the same for each user query.
I say easy *innefficnet because you search the text file for each user query each time a name is entered. To do it properly, you should probably build a dictionary of all names and their information. But that solution is more complicated, and you are only a week in! Moreover, its longer and you should give it a try. Look up dict.
I believe the reason you are not seeing the field the second time around is because the iterator returned by csv.DictReader() is a one-time iterator. That is to say, once you've reached the last row of the csv file, it will not reset to the first position.
So, by doing this:
data = csv.DictReader(open("C:\file.csv"))
for row in data:
print row
You are running it out. Try commenting those lines and see if that helps.

Categories

Resources