Python: Printing data only when number enters or leaves interval - python

Currently I'm making a script that, given a set of celestial coordinates, will tell you on the next days when that point will be visible for a specific telescope. The criteria is simple, in the Horizontal Coordinate system, altitude of the object must be between 30 and 65 degrees(Variable "crit" here represents that, but in radians).
So I have a set of parameters for the telescope called "Ant" and then, using Pyephem:
#imported ephem as ep
obj= ep.FixedBody()
obj._ra= E.ra
obj._dec= E.dec
obj._epoch = E.epoch
Ant.date = ep.now()
for d in range(days):
for i in range(24):
for j in range (60):
Ant.date += ep.minute
obj.compute(Ant)
crit= float(obj.alt)
if crit>=0.523599 and crit <=1.13446:
print "Visible at %s" %Ant.date
Which results in printing a lot of "Visible at 2016/7/11 19:41:21", 1 for every minute.
I Just want it to print something like "Enters visibility at 2016/7/11 19:41:21, leaves at 2016/7/11 23:41:00", for example.
Any Ideas will be appreciated.
Disclaimer: Sorry, not a native english speaker.

You need to keep track of whether it is already in range. So, for instance, at the beginning you'd initialize it:
is_visible = False
and your if statement might look like:
if crit>=0.523599 and crit <=1.13446:
if not is_visible:
print "Visible at %s" %Ant.date
is_visible = True
else:
if is_visible:
print "No longer visible at %s" % Ant.date
is_visible = False

Related

What is the def paradox_stats() function in my code?

I am trying to learn how to write a function that could test the probability of same birthday of two people in a room.
The birthday paradox says that the probability that two people in a room will have the same birthday is more than half, provided n, the number of people in the room, is more than 23. This property is not really a paradox, but many people find it surprising. Design a Python program that can test this paradox by a series of experiments on randomly generated birthdays, which test this paradox for n = 5,10,15,20,... ,100.
Here is the code that showed in my book.
import random
def test_birthday_paradox(num_people):
birthdays = [random.randrange(0,365) for _ in range(num_people)]
birthday_set = set()
for bday in birthdays:
if bday in birthday_set: return True
else: birthday_set.add(bday)
return False
def paradox_stats(num_people = 23, num_trials = 100):
num_successes = 0
for _ in range(num_trials):
if test_birthday_paradox(num_people): num_successes += 1
return num_successes/num_trials
paradox_stats(31)
0.77
I can't understand the code from def paradox_stats to the end of code.
Can someone help me , please?
Guessing that paradox_state(31) is a mistake and you want to write paradox_stats(31):
def paradox_stats(num_people = 23, num_trials = 100): is the definition of the function where two variables could be inserted (these variables are optional).
num_successes = 0 the code are initializing the variable num_successes to zero.
for _ in range(num_trials):
if test_birthday_paradox(num_people): num_successes += 1
return num_successes/num_trials
Here the code is running throw a range from 0 to the number of trials which the user could define once is calling the function (remember it is an optional variable).
In this loop the code is using the previous function test_birthday_paradox (which I suppose you understand as far as you say in your question) to know if someone in the room has the same birthday. In the case that the function returns True (someone has the same birthday) the variable num_successes increase its value in one (this is how works += syntax, but if you need further explanation num_successes+=1 == num_successes = num_successes+1).
And once the loop is completed the function paradox_stats return the probability in the random sample as the number of successes vs number of trials.
Hope my answer can help you.

Shortening an if, elif, elif else clause

I am making a program that checks when the next train leaves. For that, it takes the departure times from a website and stores them in arrays(times_luz and times_hitz).
However, the API sometimes doesn't have any Information, so there's no data in the array which, later in the code, leads to an error, Therefore I thought this would be a good Idea:
if times_hitz and times_luz:
Code to be executed if both contain values
elif times_luz:
Code to be executed if only times_luz contains values
elif times_hitz:
Code to be executed if only times_hitz contains values
else
print("No content available")
sys.exit()
This would technically work, but the code is currently about 30 lines long so I would have to Copy & Paste that Code 2 times with only slight changes. This would lead to about 80 lines of code and would look pretty ugly. Is there any better way of doing this?
Edit:
I made a huge mistake in guessing the size of my file, it's actually 103 lines long, including comments. Therefore, I decided to upload it to google drive:
https://drive.google.com/open?id=1F5FIuAy_g7sC_2wTprqg3EF_m_JXEreL
The error that occurs when there's no data in the array is on line 44 and 48 because the 1st item in the Array times_luz/hitz doesn't exist and can therefore not be saved to a variable. This means that I have to execute some code that only checks the _luz trains if there's nothing in times_hitz and the other way around. If both contain data, I want to execute the code I have on google drive and if neither contains data, it should print an error message.
The endings _luz and _hitz stand for Lucerne and Hitzkirch, the two ways a train can go at my station
This code basically takes times from a Train API and stores them in 3 different variables. It then checks the 3 times and stores the one that will depart next in a variable. It does this for _luz and _hitz. In the end, it checks which train(_luz or _hitz) departs earlier and prints the difference between datetime.now and the train departure time
Sorry if my explanation is unclear, feel free to ask more questions in the comments
There is some massive duplication in your code. Basically, the entire code for getting the next train is the same for the two destination (and any other destinations you might add later) and should be moved to a function.
def get_next_train(params):
res =requests.get(base, params=params)
parsed_json = res.json()
#Zeiten aus parsed_json extrahieren
time_strings = [d["from"]["prognosis"]["departure"]
for d in parsed_json["connections"]]
#String, um Zeiten in time_strings nach ISO 8601 zu parsen
iso_format = "%Y-%m-%dT%H:%M:%S%z"
# Time Strings zu datetime Objekten konvertieren
times = [datetime.strptime(ts, iso_format)
for ts in time_strings if ts is not None]
# Checken, ob times leer sind
if not times:
return None # CHANGE: return None if no times found
#Zeitzone der ersten zeit in Times speichern
tz = times[0].tzinfo
#jetztige Zeit mit Zeitzone tz, Mikrosekunden löschen
nowtime = datetime.now(tz).replace(microsecond=0)
# Checken, ob Time_1 noch in der Zukunft ist. Wenn ja, diese Zeit als Time_luz speichern
time = min(t for t in times[0:3] if t > nowtime) # CHANGE: use min
return time, time - nowtime
Then, you can get the results for the two destinations, and get the min after filtering results that are None, then just check whether that min is None (the default).
res_luz = get_next_train(params_luz)
res_hitz = get_next_train(params_hitz)
res = min(filter(None, (res_luz, res_hitz)), default=None)
if res is not None:
time, diff = res
print ("Next train", time, ", in", str(diff))
else:
print("Service nicht verfügbar")
Update: It seems like late in the evening, there might be no train departing after nowtime, causing the min to raise an exception. You can fix this by providing another default like below and returning None in this case, too.
time = min((t for t in times if t > nowtime), default=None)
return (time, time - nowtime) if time is not None else None
Update: If you want to know the destination of the next train (makes sense...) you can get it from the parameters and return it alongside the time and diff.
return time, time - nowtime, params["to"]
then unpack and print it:
if res is not None:
time, diff, dest = res
print ("Next train to %s at %s (in %s)" % (dest, time, diff))
you can instead make a definition in Python instead, so you define it once. And where ever you need to use this definition again, you can simply call it. You can also make it a class once this function gets more complicated.
Your code will be this instead:
def train_time(times_hitz, time_luz):
if times_hitz and times_luz:
Code to be executed if both contain values
elif times_luz:
Code to be executed if only times_luz contains values
elif times_hitz:
Code to be executed if only times_hitz contains values
else:
print("No content available")
sys.exit()
return leave
Where the "leave" will be from your executed code to determine when the next train leaves. And whenever you need to evaluate if the train is leaving, simply do:
leave = train_time(times_hitz, time_luz)

Python issue with replace statement?

I've been write this practice program for while now, the whole purpose of the code is to get user input and generate passwords, everything almost works, but the replace statements are driving me nuts. Maybe one of you smart programmers can help me, because I'm kinda new to this whole field of programming. The issue is that replace statement only seems to work with the first char in Strng, but not the others one. The other funcs blower the last run first and then the middle one runs.
def Manip(Strng):
#Strng = 'jayjay'
print (Strng.replace('j','h',1))
#Displays: 'hayjay'
print (Strng.replace('j','h',4))
#Displays: 'hayhay'
return
def Add_nums(Strng):
Size=len(str(Strng))
Total_per = str(Strng).count('%')
# Get The % Spots Position, So they only get replaced with numbers during permutation
currnt_Pos = 0
per = [] # % position per for percent
rGen = ''
for i in str(Strng):
if i == str('%'):
per.append(currnt_Pos)
currnt_Pos+=1
for num,pos in zip(str(self.ints),per):
rGen = Strng.replace(str(Strng[pos]),str(num),4);
return rGen
for pos in AlphaB: # DataBase Of The Positions Of Alphabets
for letter in self.alphas: #letters in The User Inputs
GenPass=(self.forms.replace(self.forms[pos],letter,int(pos)))
# Not Fully Formatted yet; you got something like Cat%%%, so you can use another function to change % to nums
# And use the permutations function to generate other passwrds and then
# continue to the rest of this for loop which will generate something like cat222 or cat333
Add_nums(GenPass) # The Function That will add numbers to the Cat%%%
print (rGen);exit()

Assigning variables from a list, or "how to make an elegant save function"

I'm currently working on a small text based game, the game remembers the gamestate based on global variables, for example, goblins_dead to see if you've killed the goblins yet.
This worked pretty well, until I decided to add a save and load function. The save function works, the load function does not, and while I know why, I can't come up with an easy fix.
The way the save function currently works is this, I have a list with all the global variables we've used in the game so far. Then I have the list run through each varaiable and give a 1 if its true or a 0 if its not, at the end it prints a "seed" that consists of a list of 1s and 0s the user can input. It looks like this, in my sample test code
def game_save():
print "This will give you a seed. Write it down, or see seed.txt"
print "When you start a new game, you will be propted to give your seed. Do so to reload."
global goblins_defeated
global lucky
global princesshelp
end = "done"
load_seed =[goblins_defeated, lucky, princesshelp, end]
load_seed.reverse()
variable = load_seed.pop()
seed = []
print globals()
while end in load_seed:
if variable == True:
seed.append("1")
print "APPENEDED 1"
print load_seed
variable = load_seed.pop()
elif variable == False:
seed.append("0")
print "APPENED 0"
print load_seed
variable = load_seed.pop()
else:
print "ERROR"
break
seedstring = ' '.join(seed)
print "This is your seed %s" %seedstring
This code works, it yields a string, that matches the values in the way I want.
The issue comes when its time to load. I inverted this process, like this:
def game_load():
print "Please type your seed in here:"
global goblins_defeated
global lucky
global princesshelp
end = "done"
seedlist = [goblins_defeated, lucky, princesshelp, end]
seed = raw_input("> ")
seed_list = seed.split(" ")
seed_value = seed_list.pop()
variable_list = [end, goblins_defeated, lucky, princesshelp]
variable = variable_list.pop()
testlist = []
while end in variable_list:
if seed_value == '1':
variable = True
print variable_list
print variable
print seed_value
elif seed_value == '0':
variable = False
print variable_list
print variable
print seed_value
else:
print "ERROR ERROR FALSE LOOP RESULT"
break
if bool(seed_list) == False:
print "List is empty"
else:
seed_value = seed_list.pop()
variable = variable_list.pop()
The mistake will be obvious to more seasoned programmers, it turns out lists load what a variable points at, not the variable name, so I can't assign things in this way.
This is where I'm stumped, I could just make a long list of if statements, but that's not very elegant. Further reading suggests that a dictionary approach might be the way to solve this, but I'm unsure on how I would go about implementing a dictionary, more specifically, I'm not sure how dictionaries interact with variables, my understanding is that this is how variables are actually stored in python, but I'm not sure how to get started on accessing and storing those variables reliably, or if I could use a global dictionary to store all my variables in the game properly. Basically, I'm unsure of how to "correctly" use a dictionary to its full potential, specifically how it interacts with variables.
That's much larger than necessary. Just use string formatting to provide the save password:
print 'Your seed is {}{}{}{}'.format(goblins_defeated+0, lucky+0, princesshelp+0, end+0)
Adding 0 converts each boolean into its numeric representation. Each value is inserted into the string, replacing the {}.
Load like this:
seed = raw_input("> ")
goblins_defeated, lucky, princesshelp, end = map(bool, map(int, seed.split()))
This splits seed on whitespace, maps each element to an integer, then maps each of those integers to a boolean, then unpacks that map object into the appropriate variables.
You don't necessarily have to store these conditions as booleans at all, as 1 and 0 will evaluate similarly, with 0 for False and 1 for True. Booleans are actually a subclass of int anyway. You can even do math with them, e.g. True+True equals 2.

Python, if statement and float

I have a function in Python that reads a ds18b20 temp sensor. The sensor gives me a faulty value (-0.062) about 5% of the time that I read it. This is not a problem but I do not want to log the value since it looks ugly in my graphs.
I can't manage to "catch" the value in an if-statement to replace it with "#error". The code below runs nicely but it appears that the if-statement is faulty and does not work - it just runs everything under the else.
I have tried everything, even "catching" all values between 1000 and 1500 (present temperature reading before dividing by 1000) to check if it would work with any temperature, but it does not.
Does anyone have any idea why my if-statement does not work?
def readtwo():
tfile = open("/sys/bus/w1/devices/28-0000040de8fc/w1_slave")
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000
if temperature == -0.062:
return("#error")
else:
return(temperature)
Testing base 10 floats for (in)equality is almost always the wrong thing to do, because they almost always cannot be exactly represented in a binary system.
From what I see of your snippet, you should compare against the string, then convert to float if it is not the dreaded -0.062:
def readtwo():
tfile = open("/sys/bus/w1/devices/28-0000040de8fc/w1_slave")
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = temperaturedata[2:]
if temperature == '-0062':
return("#error")
else:
temperature = float(temperature) / 1000
return(temperature)
You might also be able to clean up the rest of the code a little:
def readtwo():
with open("/sys/bus/w1/devices/28-0000040de8fc/w1_slave", 'r') as f:
secondline = f.readlines()[1]
temp = secondline.split(' ')[9][2:]
if '-62' in temp:
return '#error'
else:
return float(temp)/1000
Regardless to my comment about the decimal module, floating point arithemitc has it's problems (in python as well). The foremost of which is that due to representation errors, two numbers that are equal on paper, will not be equal when compared by the program.
The way around it, is to look at the relative error between two numbers, rather than simply compare them.
in pseudo:
if abs(num1 - num2)/ abs(num2) < epsilon:
print "They are close enough"
And in your case:
if abs(temparture + 0.062)/0.062 < 10**-3:
return("#error")
Basically, we check that the numbers are "close enough" to be considered the same.

Categories