Arcpy SelectLayerByLocation giving an error - python
this script is supposed to select features within distance in two layers based on some their characteristics one feature will get a score (example: water pipes crossing naturally sensitive areas like rivers, the type of that river and its permanency matter in the scoring, so each type will be selected then used in select by lactation function to give water pipes that are within a distance its score
this is the error I get when i run these codes:
Executing: SelectLayerByLocation water_mains WITHIN_A_DISTANCE Just_selected "2.5 Meters" NEW_SELECTION
Start Time: Thu Sep 25 15:21:09 2014
ERROR 999999: Error executing function.
A column was specified that does not exist.
A column was specified that does not exist.
Failed to execute (SelectLayerByLocation).
the select layer by location is in a script that is called by another script (main script)
the main script :
def main():
try:
import arcpy
from arcpy import env
# pathing to avoid retyping
env.workspace = "C:/Users/abusheikan/Desktop/prev_files/RiskAnalysisModel"
dataPath = 'C:\\Users\\abusheikan\\Desktop\\prev_files\\RiskAnalysisModel\\ToolData2'
arcpy.env.overwriteOutput = True
import imp
##Defines INPUT variables
#some variable wont be used but are there for future use, I'm starting off as simple as possible
creekLayer = dataPath + "\\ENVIRONMENTAL\\OHN_WaterCourse.shp"
PipeLayer=dataPath + "\\SERVICES\\water_mains.shp"
nameField = 'ROW_1'
scoreField = 'ROW_SCORE1'
crossingField = 'CROSS_ROW1'
ROWfield = 'ROW_TRUE1'
diaField='INTERNAL_D'
rangeVal= 416
Field = 'WARTERCOURS'
Field2='PERMANENCY'
arcpy.MakeFeatureLayer_management(PipeLayer,"water_mains")
inFeatures = "water_mains"
#The following lists contain road classes. Format is (a, b, c,d) such that a is the creek class name,
#b is an average permencnacy of flow, c is the width, nd d is the xscore to be given .
#Lower value of c means lower criticality.
creeks = [('Vertual Flow','intermittent',10,1),
('Vertual Connector','intermittent', 10,2),
('Vertual Flow','Permanent', 10,1),
('Vertual Connector', 'Permanent', 10,2),
('Ditch','Intermittent',5,3),
('Ditch','Permanent',5,4),
('Stream','Intermittent',5,3),
('Stream','Intermittent',5,4)]
## the following isnt used yet
creeks2 = [('Vertual Flow','intermittent',10,1),
('Vertual Connector','intermittent', 10,2),
('Vertual Flow','Permanent', 10,1),
('Vertual Connector', 'Permanent', 10,2),
('Ditch','Intermittent',5,3),
('Ditch','Permanent',5,4),
('Stream','Intermittent',5,3),
('Stream','Intermittent',5,4)]
## This codeblock isnt utilized yet and will always return row_score, it is supposed to adjusts the value of ROW_SCORE
##based on whether the water main crosses a creek, by looking up the value in CROSS_ROW1 feild that is obtained later on
expression = "crossing(!CROSS_ROW1!,!ROW_SCORE1!)"
codeblock = """def crossing(crosses, row_score):
if crosses != 0:
return 5
else:
return row_score"""
except:
arcpy.AddError("Definitions failed")
arcpy.AddMessage(arcpy.GetMessages())
try:
## pathing to a funtion to be called
fpath = 'C:\\Users\\abusheikan\\Desktop\\prev_files\\RiskAnalysisModel\\Scripts\\'
## defining the function pathing we retyped anyway for debugging purpuses.
functions = imp.load_source('functions', 'C:\\Users\\abusheikan\\Desktop\\prev_files\\RiskAnalysisModel\\Scripts\\functions_creeks.py')
## check check :-p
arcpy.AddMessage("Funtions Loaded")
except:
arcpy.AddMessage("Functions not loaded")
try:
##Clear all selections, because otherwise commands will be applied only to selected features, why? I ont know pls explain where this is
## supposed to be used and where not to. THANKs!
arcpy.SelectLayerByAttribute_management(inFeatures, "CLEAR_SELECTION")
arcpy.AddMessage("Selected")
##This new field will show the road overlying the pipe. Default value of "no Creek" will be assigned.
arcpy.AddField_management(inFeatures, nameField, "TEXT")
arcpy.CalculateField_management(inFeatures, nameField, '"No Creek"')
##This field will contain a score for the highest creek class over the pipe.
## Default of 0 means no creeks
arcpy.AddField_management(inFeatures, scoreField, "SHORT")
arcpy.CalculateField_management(inFeatures, scoreField, 1)
arcpy.AddField_management(inFeatures, crossingField, "SHORT")
## arcpy.AddField_management(mainRoadLayer, ROWfield, "FLOAT",3,1)
## arcpy.CalculateField_management("t_Pavement_Line", ROWfield, expressionROW, "PYTHON_9.3", codeblockROW)
except:
#Report error
arcpy.AddError("Could not create new fields")
#Report error messages
arcpy.AddMessage(arcpy.GetMessages())
try:
## functions.roadclass_loop is a function that loops through all creek classes in
## a list, selects the water mains within a distance of each one, and assigns the
## appropriate score. Full script is in the called function.
## the following s a failed test so never mind that commented out line, it may ciome in handy so left it in there
## arcpy.MakeFeatureLayer_management(PipeLayer,
## "JUST_MADE",str(dialField) + " <= "+ str(rangeVal))
## calls creek_loop funtion() i think here is where the error is created pls check the inputs they may be where problem is! but i cant see anything wrong with them.
functions.roadclass_loop(creeks, creekLayer, Field, inFeatures, "WITHIN_A_DISTANCE",
nameField, scoreField)
arcpy.AddMessage("small pipes")
## same as b4 but with the second tuple list.
functions.roadclass_loop(creeks2, creekLayer, Field, inFeatures, "WITHIN_A_DISTANCE",
nameField, scoreField)
arcpy.AddMessage("BIG PIPES")
## functions.roadclass_loop(provincial, provincialLayer, Field3, inFeatures, "INTERSECT",
## "", crossingField)
## If the CROSS_ROW field has a nonzero value (i.e. if the water main crosses a large road)
## the road class score will be increased to 5(the maximum).
## inserts the scores into the
arcpy.CalculateField_management(inFeatures, scoreField, expression, "PYTHON_9.3", codeblock)
except:
arcpy.AddMessage("Could not run")
arcpy.AddMessage(arcpy.GetMessages())
if __name__== "__main__":
main()
the called function is:
def test():
## import arcpy
arcpy.AddMessage("This function works")
##def roadclass_loop(listOfClassTuples, sourceLayer, fieldName, targetLayer,
## outputField1, outputField2):
def roadclass_loop(listOfClassTuples, sourceLayer, fieldName, targetLayer, crossingType,
outputField1, outputField2):
import arcpy
from arcpy import env
env.workspace = "C:/data/"
##try:
for creekclass in listOfClassTuples:
(classname, Permanency, creekWidth, score) = creekclass
bufferDistance = creekWidth*0.5
try:
if crossingType == "INTERSECT":
stringBuffer = ""
else:
stringBuffer = "%s Meters" % str(bufferDistance)
except:
arcpy.AddMessage("its here")
arcpy.MakeFeatureLayer_management(sourceLayer, "Just_selected",
fieldName + "= '"+ classname + "'")
#arcpy.MakeFeatureLayer_management("Just_Selected", "JUST_SELECTED", FieldName2+" = '"+ Permanency + "'")
arcpy.SelectLayerByLocation_management(targetLayer, crossingType,
"Just_selected", stringBuffer, "NEW_SELECTION")
classname = classname.lower()
if outputField1!= "":
arcpy.CalculateField_management(targetLayer, outputField1, classname )
arcpy.CalculateField_management(targetLayer, outputField2, score )
arcpy.Delete_management("Just_selected")
arcpy.SelectLayerByAttribute_management(targetLayer, "CLEAR_SELECTION")
##except:
# arcpy.AddMessage("Function failed")
#arcpy.AddMessage(arcpy.GetMessages())
See this question on the GIS StackExchange: Points in Polygon Count: Error with arcpy.selectLayerByLocation_management . They made a mistake when calling MakeFeatureLayer_management, but the error was thrown by SelectLayerByLocation_management. You may have a similar situation.
In your case, are you confident that the feature class stored in dataPath + "\\ENVIRONMENTAL\\OHN_WaterCourse.shp" has a field called WARTERCOURS? Is there maybe a typo there? (The word WARTERCOURS caught my attention; Google says you're the first person on the Internet to use it.)
Is your listOfClassTuples, which is being fed by your creeks variable, supposed to be set of fields within your creekLayer (dataPath + "\ENVIRONMENTAL\OHN_WaterCourse.shp)?
Related
Generate a text file according to the successful steps. - Possible improvement of the code or other way of doing it?
I would like to keep track of the steps taken by the program in a text report file. Each step in the code returns a dataframe and there is a dependency between tasks (task n cannot be executed if task n-1 had found nothing). My programme looks like this: (kind of pseudo code) import pandas as pd step_1 = find_stuff() if not step_1.empty: step_2 = find_new_stuff() if not step_2.empty: step_3 = find_new_stuff_again() if not step_3.empty: report (step_1, step_2, step_3) else: report (step_1, step_2, step_3=pd.DataFrame()) else: report (step_1, step_2=pd.DataFrame(), step_3=pd.DataFrame()) else: report (step_1=pd.DataFrame(), step_2=pd.DataFrame(), step_3=pd.DataFrame()) def report (step_1, step_2, step_3) : report_file = open("report.txt", "a") if not step_1.empty: report_file.write(f'Here what was found for step 1 \n : { step_1} \n') if not step_2.empty: report_file.write(f'Here what was found for step 2 \n : { step_2} \n') if not step_3.empty: report_file.write(f'Here what was found for step 3 \n : { step_3} \n') else: report_file.write('Nothing was found \n') This way of doing things is very basic but does what I ask it to do. Though, I was wondering if there was a way to avoid/reduce all these "if" or an alternative way to generate this kind of report?
My answer is similar to #Nik's so that you need to iterate over some functions but I added it to a class so you can have the state together with the functions in the same scope. I also changed you file opening to use with as it is considered the safe way to handle files: class StepFailedException(Exception): pass class StuffFinder: def __init__(self): self.findings = [] def find_stuff_1(self): stuff = None # find stuff if stuff.empty: raise StepFailedException self.findings.append(stuff) def find_stuff_2(self): stuff = None # find stuff if stuff.empty: raise StepFailedException self.findings.append(stuff) def find_stuff_3(self): stuff = None # find stuff if stuff.empty: raise StepFailedException self.findings.append(stuff) def report(self): if self.findings: with open("report.txt", "a") as report_file: for i,stuff in enumerate(self.findings): report_file.write(f'Here what was found for step {i+1} \n : { stuff } \n') def clear(self): self.findings.clear() def find_stuff(self): self.clear() try: self.find_stuff_1() self.find_stuff_2() self.find_stuff_3() except StepFailedException as e: # handle exception if necessary pass self.report() sf = StuffFinder() # you could add some initial values as argument to the constructor sf.find_stuff() # OR go step by step sf.clear() sf.find_stuff_1() # sf.find_stuff_2() let's skip this one sf.find_stuff_3() sf.report()
In principle, I think your code is readable and gets the job done. However, if you have a lot of steps, you might want to iterate over them. Here is an example: import pandas as pd def report(steps): report_file = open("report.txt", "a") for i, s in enumerate(steps): report_file.write(f"Here what was found for step {i+1} \n : { s} \n") steps = [] find_functions = [find_stuff, find_new_stuff, find_new_stuff_again] for f in find_functions: found_stuff = f() if found_stuff.empty: break steps.append(found_stuff) report(steps) Also, mind that you are currently opening your report in "a" mode, so it will append results if you rerun the code.
Arcpy.python ArcServer sde permissions
I have this python script that basically selects a point by it's ID, then selects all points within a distance and returns only a subset of those that match the type field. i.e. find all hospitals within 3 miles of this location.. My python script works, does what it's supposed to. So I create a GP service from it. Add the service back into the map and run it. Now I notice no matter what distance I use, the data doesn't change. If I delete the created Featureclass to see if it's really working. It does not create a new featureclass but it says it completed successfully. Now the weird part, if I hit the GP service at the rest endpoint with the parameters it says it works but returns no records. I've been careful to avoid schema locks when using the Rest endpoint ArcMap and ArcCatalog are closed. It's like the GP service doesn't have permission to write to the sde database, However my sde connection works fine on my PC. Any ideas? import arcpy, os, string from arcpy import env db = r"Connection to racdev1.sde" theworkspace = r"Connection to racdev1.sde" arcpy.env.workspace = theworkspace arcpy.env.overwriteOutput = True #facilityID = '1249' facilityID = arcpy.GetParameterAsText(0) #facilityIDType= 'PFI' facilityIDType = arcpy.GetParameterAsText(1) thedistance = arcpy.GetParameterAsText(2) #thedistance = '3 miles' #withindistance = "3 Miles" withindistance = thedistance + ' Miles' sql_query = "\"%s\" = '%s'" % ("ID", facilityID) sql_query2 = "\"%s\" = '%s'" % ("IDTYPE", facilityIDType) # Local variables: Facilities = "DOHGIS.NYSDOH_CI_DATA" featLayer = "thePts" arcpy.MakeFeatureLayer_management(Facilities, featLayer) # Process: Select Layer By Attribute arcpy.SelectLayerByAttribute_management(featLayer, "NEW_SELECTION", sql_query) # Process: Select Layer By Location 311 arcpy.SelectLayerByLocation_management(featLayer, "WITHIN_A_DISTANCE",featLayer, withindistance, "NEW_SELECTION") #print " now for the subset" arcpy.SelectLayerByAttribute_management("thePts", "SUBSET_SELECTION", sql_query2 ) # creaate the new featureclss.. arcpy.CopyFeatures_management("thePts",'DOHGIS.NYSDOH_FacilitiesQuery') #print "Done"
ArcMap 10.2: Custom ArcGIS tool.
I am trying to modify the first script and convert it into a custom ArcGIS tool. The first script takes to shapefiles and converts them to feature layers then intersects the new feature layers and finally copies the output to a ne shapefile. This portion of the script works. The second script is suppose to be a modified version of the first script. Most of the script appears to work except for the count= int(arcpy.GetCount_management("output_features").getOutput(0)), the arcpy.AddMessage and the arcpy.AddWarning portions. I am not sure if the script is correct for count = int(arcpy.GetCount_management("output_features").getOutput(0)) Currently the arcpy.AddMessage returns "A new feature class (the full path of the output_features) the out has been created!" I want it to say "A new feature class 'selected_parcels' has been created!" Furthermore, I want arcpy.AddWarning to return the number of rows in in selected_parcels. Currently I am getting an error indicating that count does not exist. #Current code: #Part I try: userWorkspace = raw_input("What is the workspace location?") input_class = raw_input("What is the input feature class name?") select_class = raw_input("What is the select feature class name?") output_class = raw_input("What is the output feature class name?") arcpy.env.workspace = userWorkspace arcpy.env.overwriteOutput = True arcpy.MakeFeatureLayer_management(input_class,"lyr") arcpy.MakeFeatureLayer_management(select_class,"select_lyr") arcpy.SelectLayerByLocation_management('lyr','intersect','select_lyr') arcpy.CopyFeatures_management("lyr",output_class) print "A new feature class",output_class," has been created!" except: print arcpy.GetMessages() #Part II import arcpy arcpy.env.workspace = r"C:\Users\tpmorris\ProgramingAndScripting\Lab 5 Data\Lab 5 Data" arcpy.env.overwriteOutput = True input_features = arcpy.GetParameterAsText(0) selected_parcels = arcpy.GetParameterAsText(1) output_features = arcpy.GetParameterAsText(2) arcpy.MakeFeatureLayer_management("coa_parcels.shp","lyr") arcpy.MakeFeatureLayer_management("floodplains.shp","select_lyr") arcpy.SelectLayerByLocation_management('lyr','intersect','select_lyr') arcpy.CopyFeatures_management("lyr","selected_parcels") count = int(arcpy.GetCount_management("output_features").getOutput(0)) arcpy.AddMessage("A new feature class" + output_features + "has been created!") arcpy.AddWarning("There are" + count + "in the new feature class.") Any guidance would be appreciated!
I believe the problem with your code is that, when you are calling arcpy.GetCount_management, you are supplying a string ("output_features") as a parameter, not your variable output_features. Something like this should work: result = arcpy.GetCount_management(output_features) count = int(result.getOutput(0)) arcpy.AddWarning("There are {0} in the new feature class.".format(count)) Good luck! Tom
Python Maya - If objectType returns "No object name specified"
I am trying to get maya to check if the listed object is a blendshape node or not. This is my code: def bake(self, *args): self.items["selection"] = cmds.ls(sl = True) self.items["shapes"] = cmds.listRelatives(self.items["selection"], ad = True) shapes = () for i in self.items["shapes"]: bs = cmds.listConnections(i, type = "blendShape", exactType = True) if cmds.objectType(bs, isType = "blendShape"): print bs It returns # Error: RuntimeError: file X:/Documents/maya/scripts\jtBakeCharacter.py line 16: No object name specified Line 16 is: if cmds.objectType(bs, isType = "blendShape"): Except that I AM specifying an object name, that object name is bs .. I have printed the result of bs and it has many objects listed. Many.
The code is redundant. You don't need most of the lines. The listConnections already ensures that you have only blendshapes. The exact problem is that you are calling something like: cmds.objectType([]) for some of those extra shapes. And this is illegal. But mostly you code can be encapsulated as follows: selected = cmds.ls(sl = True, dag=True ,shapes = True) blends = cmds.listConnections(selected , type = "blendShape", exactType = True) for item in blends: print item But this may not catch your intent perfectly, but shows how may extra steps you take. In reality you don't need the line if cmds.objectType(bs, isType = "blendShape"): for anything
Joojaa's answer is elegant, but you can get it down even shorter by using the default selection behavior: blendshapes = cmds.ls(cmds.listHistory(pdo=True), type='blendShape') or [] for item in blendshapes: print item (In the quest to make it even shorter I'm not checking for the selection, so this one fails if nothing is selected). PS: if you need to get to the blendshape from one of the upstream shapes, instead of the deformed shape, you can use listHistory (f=True)
You could try this: from pymel.core import * for obj in selected(): shapeNode = obj.getChildren()[0] for output in shapeNode.outputs(): if nodeType(output) == "blendShape": print obj, "is a blendshape"
Condense Datetime Code, Hook Appindicator3 Menu Call + Relative Icon Path, Code Review
Hello, I am a novice to this (please answer like so for me). All of the code should run easily after fixing my (second) question. It actually runs great on my machine, but probably not yours yet. I have tried to comment everywhere for you to make it easier for someone to read. This runs on an Ubuntu 12.10 machine, but you don't need to be running Linux to help my issues! SOLVED 1. Code Review: As you go through the code, I would appreciate any input on how to condense or do things in a better, more appropriate way. The rest of my questions are really just the things I already know should be worked on. But if there's something else you find in my coding style, et al, please be candid. Upvotes to all good comments. SOLVED: 2. Relative Icon Path: At the following: /home/mh00h/workspace/issindicator/src/International_Space_Station_clip_art.svg This is an absolute path to the same folder as this script. I don't want that,, I want this script to work on anybody's machine. I tried these: $HOME/workspace... (nothing in front) International_Space_Station_clip_art.svg ./International_Space_Station_clip_art.svg but those didn't work. The image above is what I am trying to use (yes, I know I have an SVG instead of png listed, imgur limitation). Here is the documentation. It talks about an ""icon-theme-path"... maybe that would do it somehow? Or perhaps there is a standard directory all programmers are expected to store icons? 3. Concentrate my datetime functions: Really, I was fortunate to get this to work at all. My way is roundabout, but as far as I can tell, it works. I'm pretty confident that there is a better way to fix that mess though!! You'll find a bunch of datetime stuff at the bottom of the script. SOLVED: 4. Appindicator3 Hook: I would love to have GTK refresh only when the menu has been called instead of running every second regardless. This was partially answered here, but I don't really understand how to implement "realize." (Hopefully this is the right place to be asking this?) Thank you! #!/usr/bin/env python import json, urllib2, time, math, datetime, os, webbrowser from dateutil import tz #indicator from gi.repository import Gtk, GObject from gi.repository import AppIndicator3 as appindicator class indicator(): def __init__(self): #######Set this to "False" if IssIndicator should hide it's icon during normal runtime (default = True) self.isiconhidden = True # #create indicator self.ind = appindicator.Indicator.new ( "issindicator", "/home/mh00h/workspace/issindicator/src/International_Space_Station_clip_art.svg", #"indicator-messages", appindicator.IndicatorCategory.APPLICATION_STATUS) if self.isiconhidden == True: self.ind.set_status (appindicator.IndicatorStatus.PASSIVE) else: self.ind.set_status (appindicator.IndicatorStatus.ACTIVE) #this is used to keep track of the gtk refresh period self.refreshvalue = False #dropdown menu #current pass menu items self.menu = Gtk.Menu() self.curpass = Gtk.MenuItem("not refreshed") self.curpass.connect("activate", self.checkiss) self.menu.append(self.curpass) self.curpassdur = Gtk.MenuItem(" ") self.menu.append(self.curpassdur) self.curpassrise = Gtk.MenuItem(" ") self.menu.append(self.curpassrise) self.curpassset = Gtk.MenuItem(" ") self.menu.append(self.curpassset) self.sep1 = Gtk.SeparatorMenuItem() self.menu.append(self.sep1) #future pass items self.futpass = Gtk.MenuItem(" ") self.futpass.connect("activate", self.onurl) self.menu.append(self.futpass) self.sep2 = Gtk.SeparatorMenuItem() self.menu.append(self.sep2) #Options items self.aboutmenu = Gtk.MenuItem("About") self.aboutmenu.connect("activate", self.onabout) self.menu.append(self.aboutmenu) self.quit = Gtk.MenuItem("Quit") self.quit.connect("activate", self.quitnow) self.menu.append(self.quit) self.curpass.show() self.sep1.show() self.futpass.show() self.sep2.show() self.aboutmenu.show() self.quit.show() self.ind.set_menu(self.menu) #get iss data at first run self.updatecache() self.checkiss() Gtk.main() #functions def hideicon(self, w=None): self.ind.set_status (appindicator.IndicatorStatus.PASSIVE) def showicon(self, w=None): self.ind.set_status (appindicator.IndicatorStatus.ACTIVE) def quitnow(self, w=None): Gtk.main_quit() #open browser for more tracking info def onurl(self, w=None): webbrowser.open("http://www.n2yo.com/passes/") def onabout(self,widget): widget.set_sensitive(False) ad=Gtk.AboutDialog() ad.set_name("aboutdialog") ad.set_version("0.1") ad.set_copyright('Copyrignt (c) 2013 mh00h') ad.set_comments('Indicating ISS Zarya') ad.set_license(''+ 'This program is free software: you can redistribute it and/or modify it\n'+ 'under the terms of the GNU General Public License as published by the\n'+ 'Free Software Foundation, either version 3 of the License, or (at your option)\n'+ 'any later version.\n\n'+ 'This program is distributed in the hope that it will be useful, but\n'+ 'WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n'+ 'or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n'+ 'more details.\n\n'+ 'You should have received a copy of the GNU General Public License along with\n'+ 'this program. If not, see <http://www.gnu.org/licenses/>.') ad.set_website('https://launchpad.net/~mh00h/+archive/issindicator') ad.set_website_label('ISSIndicator Homepage') ad.set_authors(['mh00h <abcd#abcd.com']) ad.run() ad.destroy() widget.set_sensitive(True) #how often to run checkiss def setrefresh(self, r): #this clause is required to keep script from hanging if r != self.refreshvalue: self.refreshvalue = r try: self.reftime = GObject.source_remove(True) except: pass try: self.reftime = GObject.timeout_add(r, self.checkiss) except: pass # def updatecache(self, w=None): #this will show in the menu until the update process completes self.passingstatus = 'not updated yet' #get ISS data from api self.ip = urllib2.urlopen("http://api.exip.org/?call=ip").read() self.geoip = json.load(urllib2.urlopen("http://freegeoip.net/json/"+self.ip)) self.data = json.load(urllib2.urlopen("http://api.open-notify.org/iss/?lat="+str(self.geoip["latitude"])+"&lon="+str(self.geoip["longitude"])+"&alt=280&n=47")) self.data = {"message": "success", "request": {"latitude": 45.0, "passes": 3, "altitude": 280, "longitude": -81.0, "datetime": 1361502063}, "response": [{"duration": 542, "risetime": time.time()+10}, {"duration": 642, "risetime": 1361560774}, {"duration": 593, "risetime": 1361566621}]} def checkiss(self, w=None): #so as to not overload api servers, this runs as a separate process #this updates the timers self.n = 0 self.passingstatus = "ISS Zarya is below the horizon" #check if we've gone through cached iss passings and update api if needed try: #ignore errors in case internet is not accessible #have a buffer of 5 passes remaining before updating cache #at 2 passes left, stop the program to prevent the rest of the program from throwing codes if time.time() > self.data['response'][len(self.data['response'])-5]['risetime']: self.updatecache except: if time.time() > self.data['response'][len(self.data['response'])-2]['risetime']: os.system("notify-send 'ISS Indicator tried multiple times to update its satellite cache but has run out of its cached track.' 'This may be due to a bad internet connection. The application will now quit.'") Gtk.main_quit() #get current time current_utc = datetime.datetime.utcnow() current_utc = current_utc.replace(tzinfo=tz.gettz('UTC')) #iterate over all iss passes for k in self.data['response']: duration = self.data['response'][self.n]['duration'] risetime = self.data['response'][self.n]['risetime'] settime = risetime + duration #if this iteration matches with the current time, do... if risetime <= time.time() <= settime: #make the countdown values for the current pass tick #rise time calculations and date conversions to string format currisetime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][self.n]['risetime']) currisetime_utc = currisetime_utc.replace(tzinfo=tz.gettz('UTC')) currisetime_tz = currisetime_utc.astimezone(tz.tzlocal()) currisetime_tzstr = str("%02d" % (currisetime_tz.hour))+':'+str("%02d" % (currisetime_tz.minute))+':'+str("%02d" % (currisetime_tz.second)) #set time calculations and durations cursettime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][self.n]['risetime']+self.data['response'][self.n]['duration']) cursettime_utc = cursettime_utc.replace(tzinfo=tz.gettz('UTC')) cursettime_tz = cursettime_utc.astimezone(tz.tzlocal()) curremainingtimeleft = cursettime_utc - current_utc curduration = cursettime_utc - currisetime_utc z= curremainingtimeleft.seconds zhours = z/60/60 zminutes = z/60-zhours*60 zseconds = z-zhours*60*60-zminutes*60 curremainingtimeleftstr = str(zhours)+':'+str("%02d" % (zminutes))+':'+str("%02d" % (zseconds)) z= curduration.seconds zhours = z/60/60 zminutes = z/60-zhours*60 zseconds = z-zhours*60*60-zminutes*60 curdurationstr = str(zhours)+':'+str("%02d" % (zminutes))+':'+str("%02d" % (zseconds)) cursettime_tzstr = str("%02d" % (cursettime_tz.hour))+':'+str("%02d" % (cursettime_tz.minute))+':'+str("%02d" % (cursettime_tz.second)) #since the ISS is presently overhead, show the icon and update GTK menuitems to show timers on the ISS pass self.showicon() self.passingstatus = "ISS Zarya is above the horizon!" self.curpass.get_child().set_text(self.passingstatus) self.curpassdur.get_child().set_text("Duration: "+curdurationstr+" ("+curremainingtimeleftstr+" remaining)") self.curpassdur.show() self.curpassrise.get_child().set_text("Rise time: "+currisetime_tzstr) self.curpassrise.show() self.curpassset.get_child().set_text("Set time: "+cursettime_tzstr) self.curpassset.show() break else: #if this iteration of ISS passes does not match with current time, then increase self.n self.n += 1 #regardless of results show the next pass time #if the ISS is overhead, use the next dictionary key for data if self.n != len(self.data['response']): nextrisetime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][self.n+1]['risetime']) else: #if the ISS is not overhead, use the first key in the dictionary nextrisetime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][0]['risetime']) #calculate the next rise time and make timers nextrisetime_utc = nextrisetime_utc.replace(tzinfo=tz.gettz('UTC')) nextrisetime_tz = nextrisetime_utc.astimezone(tz.tzlocal()) remainingtimeleft = nextrisetime_utc - current_utc z= remainingtimeleft.seconds zhours = z/60/60 zminutes = z/60-zhours*60 zseconds = z-zhours*60*60-zminutes*60 remainingtimeleftstr = str(zhours)+':'+str("%02d" % (zminutes))+':'+str("%02d" % (zseconds)) nextrisetime_tzstr = str("%02d" % (nextrisetime_tz.hour))+':'+str("%02d" % (nextrisetime_tz.minute))+':'+str("%02d" % (nextrisetime_tz.second)) #update GTK menuitem self.futpass.get_child().set_text("Next Pass: "+nextrisetime_tzstr+" ("+remainingtimeleftstr+")") #if the ISS is not above the horizon, refresh GTK only once its time for the icon to be visible if self.passingstatus != "ISS Zarya is above the horizon!": self.setrefresh(remainingtimeleft.seconds*1000+100) #self.setrefresh(1000) self.curpass.get_child().set_text(self.passingstatus) self.curpassdur.hide() self.curpassrise.hide() self.curpassset.hide() if self.isiconhidden == True: self.hideicon() else: #otherwise, refresh once a second to show the timers ticking in the menu #test if the menu is active instead of always running like in this example ####MISSING CODE HERE##### DONT KNOW HOW TO DO IT, SO JUST SETTING TO 1 SEC self.setrefresh(1000) #for when setrefresh calls this function return True if __name__ == '__main__': issindicator = indicator()