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)
Related
I have a file here that asks the user for a city/county, reads the file to find any lines with the city or county they specified, and in the end the program should print the date that the number of increase in cases was highest.
def main():
#open the file
myFile = open("Covid Data.txt")
#read the first line
firstLine = myFile.readline()
#set current, previous, and greatest to 0
current = 0
previous = 0
greatest = 0
#ask user for a city/county name
userLocation = input("Please enter a location ").title
#for each line in the file
for dataLine in myFile:
#strip the end of the line
dataLine = dataLine.rstrip("\n")
#split the data line by the commas and place the parts into a list
dataList = dataLine.split(",")
#if dataList[2] is equal to location
if dataList[2] == userLocation:
#subtract previous from current to find the number of cases that the total increased by
cases = current - previous
#if cases is higher than what is currently set as the greatest
if cases > greatest:
#set the new greatest to amount of cases
greatest = cases
#save the date of the current line
date = str(dataList[0])
#At the end print the data for the highest number of cases
print("On",date," ",location," had the highest increase of cases with ",cases," cases.")
#close file
For some reason, every time I run the code, after I type in what city/county I want to view information for, I keep getting an UnboundLocalError for the variable "date". It tells me that it was referenced before assignment, even though I clearly define it. Why am I getting this error?
You will need to initialize a value for the date variable before entering the loop. For example date = None. Same with cases. The problem is that if there is no valid data available, the date in the loop never gets set and thus doesn't exist.
You also are not altering the values of current or previous, which might be the cause for the bug you're seeing where the date variable never gets set (cases will always get value 0 in the loop).
Also there is a typo in the print, where you try to use location instead of the actual variable called userLocation.
My friend, you are having the problem of locals() and globals() attribute.
I am quite sure, If you put:
globals()[date]= str(dataList[0])
you won't have this problem anymore. Check this page, in 5 minutes you will understand:
https://www.geeksforgeeks.org/global-local-variables-python/
Your code has more defects.
The title is a method so you have to use as .title().
You have to define your variables outside of conditions.
The location variable is undefined in your print function.
I have written a working version from your code.
Code:
def main():
# open the file
myFile = open("Covid Data.txt")
# read the first line
firstLine = myFile.readline()
# set current, previous, and greatest to 0
current = 0
previous = 0
greatest = 0
cases = 0
date = None
# ask user for a city/county name
userLocation = input("Please enter a location ").title()
# for each line in the file
for dataLine in myFile:
# strip the end of the line
dataLine = dataLine.rstrip("\n")
# split the data line by the commas and place the parts into a list
dataList = dataLine.split(",")
print(dataList)
# if dataList[2] is equal to location
if dataList[2] == userLocation:
# subtract previous from current to find the number of cases that the total increased by
cases = current - previous
# if cases is higher than what is currently set as the greatest
if cases > greatest:
# set the new greatest to amount of cases
greatest = cases
# save the date of the current line
date = str(dataList[0])
# At the end print the data for the highest number of cases
print("On", date, " ", userLocation, " had the highest increase of cases with ", cases, " cases.")
myFile.close()
main()
Covid Data.txt:
First line
2020.12.04,placeholder,Miami
Test:
>>> python3 test.py
Please enter a location Texas
On None Texas had the highest increase of cases with 0 cases.
>>> python3 test.py
Please enter a location Miami
On None Miami had the highest increase of cases with 0 cases.
NOTE:
As you can see above, your logic doesn't work but the script can run. Some of conditions will be always False. For example because of this the date variable won't get value so it will be always None.
I've been trying to create a program which allows users to view a text file's contents and delete some or all of a single entry block.
An example of the text's file contents can be seen below:
Special Type A Sunflower
2016-10-12 18:10:40
Asteraceae
Ingredient in Sunflower Oil
Brought to North America by Europeans
Requires fertile and moist soil
Full sun
Pine Tree
2018-12-15 13:30:45
Pinaceae
Evergreen
Tall and long-lived
Temperate climate
Tropical Sealion
2019-01-20 12:10:05
Otariidae
Found in zoos
Likes fish
Likes balls
Likes zookeepers
Big Honey Badger
2015-06-06 10:10:25
Mustelidae
Eats anything
King of the desert
As such, the entry block refers to all lines without a horizontal space.
Currently, my progress is at:
import time
import os
global o
global dataset
global database
from datetime import datetime
MyFilePath = os.getcwd()
ActualFile = "creatures.txt"
FinalFilePath = os.path.join(MyFilePath, ActualFile)
def get_dataset():
database = []
shown_info = []
with open(FinalFilePath, "r") as textfile:
sections = textfile.read().split("\n\n")
for section in sections:
lines = section.split("\n")
database.append({
"Name": lines[0],
"Date": lines[1],
"Information": lines[2:]
})
return database
def delete_creature():
dataset = get_dataset()
delete_question = str(input("Would you like to 1) delete a creature or 2) only some of its information from the dataset or 3) return to main page? Enter 1, 2 or 3: "))
if delete_question == "1":
delete_answer = str(input("Enter the name of the creature: "))
for line in textfile:
if delete_answer in line:
line.clear()
elif delete_question == "2":
delete_answer = str(input("Enter the relevant information of the creature: "))
for line in textfile:
if delete_answer in line:
line.clear()
elif delete_question == "3":
break
else:
raise ValueError
except ValueError:
print("\nPlease try again! Your entry is invalid!")
while True:
try:
option = str(input("\nGood day, This is a program to save and view creature details.\n" +
"1) View all creatures.\n" +
"2) Delete a creature.\n" +
"3) Close the program.\n" +
"Please select from the above options: "))
if option == "1":
view_all()
elif option == "2":
delete()
elif option == "3":
break
else:
print("\nPlease input one of the options 1, 2 or 3.")
except:
break
The delete_function() is meant to delete the creature by:
Name, which deletes the entire text block associated with the name
Information, which deletes only the line of information
I can't seem to get the delete_creature() function to work, however, and I am unsure of how to get it to work.
Does anyone know how to get it to work?
Many thanks!
Your problem with removing lines from a section is that you specifically hardcoded which line represents what. Removing a section in your case will be easy, removing a line will, if you do not change your concept, involve setting the line in question to empty or to some character representing the empty string later.
Another question here is, do you need your sections to remain ordered as they were entered, or you can have them sorted back in a file in some other order.
What I would do is to change the input file format to e.g. INI file format. Then you can use the configparser module to parse and edit them in an easy manner.
The INI file would look like:
[plant1]
name="Some plant's English name"
species="The plant's Latin species part"
subspecies="The plant's subspecies in Latin ofcourse"
genus="etc."
[animal1]
# Same as above for the animal
# etc. etc. etc.
configparser.ConfigParser() will let you load it in an dictionarish manner and edit sections and values. Sections you can name animal1, plant1, or use them as something else, but I prefer to keep the name inside the value, usually under the name key, then use configparser to create a normal dictionary from names, where its value is another dictionary containing key-value pairs as specified in the section. And I reverse the process when saving the results. Either manually, or using configparser again.
The other format you might consider is JSON, using the json module.
Using its function dumps() with separators and indentation set correctly, you will get pretty human-readable and editable output format. The nice thing is that you save the data structure you are working with, e.g. dictionary, then you load it and it comes back as you saved it, and you do not need to perform some additional stuff to get it done, as with configparser. The thing is, that an INI file is a bit less confusing for an user not custom to JSON to construct, and results in less errors, while JSON must be strictly formatted, and any errors in opening and closing the scopes or with separators results in whole thing not working or incorrect input. And it easily happens when the file is big.
Both formats allows users to put empty lines wherever they want and they will not change the way the file will be loaded, while your method is strict in regard to empty lines.
If you are expecting your database to be edited only by your program, then use the pickle module to do it and save yourself the mess.
Otherwise you can:
def getdata (stringfromfile):
end = {}
l = [] # lines in a section
for x in stringfromfile.strip().splitlines():
x = x.strip()
if not x: # New section encountered
end[l[0].lower()] = l[1:]
l = []
continue
end.append(x)
end[l[0].lower()] = l[1:] # Add last section
# Connect keys to numbers in the same dict(), so that users can choose by number too
for n, key in enumerate(sorted(end)):
end[n] = key
return end
# You define some constants for which line is what in a dict():
values = {"species": 0, "subspecies": 1, "genus": 2}
# You load the file and parse the data
data = getdata(f.read())
def edit (name_or_number, edit_what, new_value):
if isinstance(name_or_number, int):
key = data[name_or_number]
else:
key = name_or_number.lower().strip()
if isinstance(edit_what, str):
edit_what = values[edit_what.strip().lower()]
data[key][edit_what] = new_value.strip()
def add (name, list_of_lines):
n = len(data)/2 # Number for new entry for numeric getting
name = name.strip().lower()
data[name] = list_of_lines
data[n] = name
def remove (name):
name = name.lower().strip()
del data[name]
# Well, this part is bad and clumsy
# It would make more sense to keep numeric mappings in separate list
# which will do this automatically, especially if the database file is big-big-big...
# But I started this way, so, keeping it simple and stupid, just remap everything after removing the item (inefficient as hell itself)
for x in data.keys():
if isinstance(x, int):
del data[x]
for n, key in enumerate(sorted(data)):
data[n] = key
def getstring (d):
# Serialize for saving
end = []
for l0, ls in d.items():
if isinstance(l0, int):
continue # Skip numeric mappings
lines = l0+"\n"+"\n".join(ls)
end.append(lines)
return "\n\n".join(end)
I didn't test the code. There might be bugs.
If you need no specific lines, you can modify my code easily to search in the lines using the list.index() method, or just use numbers for the lines if they exist when you need to get to them. For doing so with configparser, use generic keys in a section like: answer0, answer1..., or just 0, 1, 2..., Then ignore them and load answers as a list or however. If you are going to use configparser to work on the file, you will get sometimes answer0, answer3... when you remove.
And a warning. If you want to keep the order in which input file gives the creatures, use ordereddict instead of the normal dictionary.
Also, editing the opened file in place is, of course, possible, but complicated and inadvisable, so just don't. Load and save back. There are very rare situations when you want to change the file directly. And for that you would use the mmap module. Just don't!
The code I am running so far is as follows
import os
import math
import statistics
def main ():
infile = open('USPopulation.txt', 'r')
values = infile.read()
infile.close()
index = 0
while index < len(values):
values(index) = int(values(index))
index += 1
print(values)
main()
The text file contains 41 rows of numbers each entered on a single line like so:
151868
153982
156393
158956
161884
165069
168088
etc.
My tasks is to create a program which shows average change in population during the time period. The year with the greatest increase in population during the time period. The year with the smallest increase in population (from the previous year) during the time period.
The code will print each of the text files entries on a single line, but upon trying to convert to int for use with the statistics package I am getting the following error:
values(index) = int(values(index))
SyntaxError: can't assign to function call
The values(index) = int(values(index)) line was taken from reading as well as resources on stack overflow.
You can change values = infile.read() to values = list(infile.read())
and it will have it ouput as a list instead of a string.
One of the things that tends to happen whenever reading a file like this is, at the end of every line there is an invisible '\n' that declares a new line within the text file, so an easy way to split it by lines and turn them into integers would be, instead of using values = list(infile.read()) you could use values = values.split('\n') which splits the based off of lines, as long as values was previously declared.
and the while loop that you have can be easily replace with a for loop, where you would use len(values) as the end.
the values(index) = int(values(index)) part is a decent way to do it in a while loop, but whenever in a for loop, you can use values[i] = int(values[i]) to turn them into integers, and then values becomes a list of integers.
How I would personally set it up would be :
import os
import math
import statistics
def main ():
infile = open('USPopulation.txt', 'r')
values = infile.read()
infile.close()
values = values.split('\n') # Splits based off of lines
for i in range(0, len(values)) : # loops the length of values and turns each part of values into integers
values[i] = int(values[i])
changes = []
# Use a for loop to get the changes between each number.
for i in range(0, len(values)-1) : # you put the -1 because there would be an indexing error if you tried to count i+1 while at len(values)
changes.append(values[i+1] - values[i]) # This will get the difference between the current and the next.
print('The max change :', max(changes), 'The minimal change :', min(changes))
#And since there is a 'change' for each element of values, meaning if you print both changes and values, you would get the same number of items.
print('A change of :', max(changes), 'Happened at', values[changes.index(max(changes))]) # changes.index(max(changes)) gets the position of the highest number in changes, and finds what population has the same index (position) as it.
print('A change of :', min(changes), 'Happened at', values[changes.index(min(changes))]) #pretty much the same as above just with minimum
# If you wanted to print the second number, you would do values[changes.index(min(changes)) + 1]
main()
If you need any clarification on anything I did in the code, just ask.
I personally would use numpy for reading a text file.
in your case I would do it like this:
import numpy as np
def main ():
infile = np.loadtxt('USPopulation.txt')
maxpop = np.argmax(infile)
minpop = np.argmin(infile)
print(f'maximum population = {maxpop} and minimum population = {minpop}')
main()
I'm working on an assignment for my computer class and I'm having a bit of trouble with a question. Question 1 and 2 kind of overlap, so I'll post both, and the code I have so far.
Question 1: Write a function called readCountries that reads a file and returns a list of countries. The countries should be read from this file, which contains an incomplete list of countries with their area and population. Each line in this file represents one country in the following format:
name, area(in km2), population
When opening the file your function should handle any exceptions that may occur. Your function should completely read in the file, and separate the data into a 2-dimensional list. You may need to split and strip the data as appropriate. Numbers should be converted to their correct types. Your function should return this list so that you can use it in the remaining questions.
This is my code for this part:
def readCountries():
countryList = []
for line in open('Countries.py', 'r'):
with open('Countries.py', 'r') as countriesFile:
countries = countriesFile.read()
countryList.append(line.strip().split())
return countryList
Question 2: Write a function called getCountry that takes a string representing a country name as a parameter. First call your answer from question 1 to get the list of countries, then do a binary search through the list and print the country's information if found.
This is my code for this part:
countryList = readCountries()
def getCountry(countryList, name):
lo, hi = 0, len(countryList) - 1
while lo <= hi:
mid = lo + (hi - lo) // 2
country = countryList[mid]
test_name = country[0]
if name > test_name:
lo = mid + 1
elif name < test_name:
hi = mid - 1
else:
return country
return countries[lo] if countries[lo][0] == name else None
The output is this: ['Canada', '9976140.0', '35295770'] which is partially what I need, but how would I get it to look like this: Canada, Area: 9976140.0, Population: 35295770?
Well, one obvious problem is this line:
readCountries()
should be like this:
countryList = readCountries()
You got half way there by having the readCountries function return the list, but you never actually assign anything to what it's returning, so it just goes off into nowhere.
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.