class IRIDA(IRIDAQueryLayout): #baseURL = "https://irida.corefacility.ca/irida-public-test/irida-api/" #baseURL = "https://irida.corefacility.ca/staging/api/" #baseURL = "http://localhost:48888/irida/api/" baseURL = "http://129.173.66.114:48888/irida/api/" #clientId = "gengis" clientId = "" # THIS NEEDS TO BE HIDDEN clientSecret = "" #clientSecret = "bledjijitFeOpEerichFeatsatHowGheibwenecWijWifciek/" username = "" password = "" service = "" token = "" selectedTaxon = set() # this will be a 1:1 mapping of Project Name to Unique ID projectMap = {} obs = [] phylo = "" def __init__(self,parent=None): IRIDAQueryLayout.__init__(self,parent) self.GBIFGeneric = GBIFGeneric() self.login = Login(self) #self.credentials = Credentials() self.SetIcon(wx.Icon(GenGIS.mainWindow.GetExeDir() + "images/CrazyEye.ico",wx.BITMAP_TYPE_ICO)) self.m_Add.SetBitmapLabel(wx.Image(GenGIS.mainWindow.GetExeDir() + "images/green_arrow_down.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Add.SetBitmapHover(wx.Image(GenGIS.mainWindow.GetExeDir() + "images/green_arrow_down_hover.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Remove.SetBitmapLabel(wx.Image(GenGIS.mainWindow.GetExeDir() + "images/red_arrow_up.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Remove.SetBitmapHover(wx.Image(GenGIS.mainWindow.GetExeDir() + "images/red_arrow_up_hover.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_IDList.Clear() self.m_Search.Enable(False) self.m_Calc.Enable(False) #fix to expand summary box enough to print two lines of text properly #Map Data if GenGIS.layerTree.GetNumMapLayers() > 0 : self.m_AddData.Enable() borders = GenGIS.layerTree.GetMapLayer(0).GetController().GetMapBorders() #check if geographic coordinates are used or some other measure; only geographic are compatible geographic = GenGIS.StudyController.IsUsingGeographic(GenGIS.study.GetController()) projected = GenGIS.StudyController.IsUsingProjection(GenGIS.study.GetController()) if(not (geographic or projected)): wx.MessageBox("Geographic coordinates are not being used in the current map file. Only geographic coordinates are compatible with MG-RAST. Geographic range will need to be manually set, and any returned data will not display correctly.","Warning") self.m_AddData.Disable() credential = Credentials(self,False) credential.OnCredentialClose("fake") # By this point the active credential should be loaded. if self.clientId and self.clientSecret: self.login.ShowModal() def ReLogin(self, event): self.login.ShowModal() # Bring the main IRIDA instance back to the foreground after running login. self.Raise() def SetClientID(self,ID): self.clientId = ID def SetClientSecret(self,secret): self.clientSecret = secret def HandleLinks(self, result, type): response = {} if type == 'label': response['label'] = ''; links = result[type] for val in links: if type=='links': response[val['rel']] = val['href'] elif type == 'label': response['label'] = response['label'] + val else: if 'name' in val: response[val['name']] = val elif 'sampleName' in val: response[val['sampleName']] = val return response def ngs_request(self, url, oauth_service, access_token,debug=False): session = oauth_service.get_session(access_token) # the raw json being fetched response = session.get(url) # print response.text if debug: print response.text result = json.loads(response.text) return result def newick_request( self, url, oauth_service, access_token, debug = False): session = oauth_service.get_session(access_token) # the raw newick being fetched response = session.request("GET",url, True,headers={'Accept':'text/plain'}) if debug: print response.text return response.text def decoder(self,returnDict): # NEEDS A WAY TO DETECT BAD PASSWORD # print returnDict # if "Error report" in returnDict: # print "error occured" # return {} iridaDict = ast.literal_eval(returnDict) if "error" in iridaDict.keys(): wx.MessageBox(iridaDict['error_description'], iridaDict['error']) return None return iridaDict def GetOauthService(self): oauth_service = OAuth2Service( client_id = self.clientId, client_secret = self.clientSecret, name="irida", access_token_url = self.baseURL + "oauth/token", base_url=self.baseURL) return oauth_service def GetParams(self): params = {'data' : {'grant_type' : 'password', 'client_id' : self.clientId, 'client_secret' : self.clientSecret, 'username' : self.username, 'password' : self.password}} return params def GetToken(self): oauth_service = self.GetOauthService() params = self.GetParams() try: # print "sandwich" access_token = oauth_service.get_access_token(decoder = self.decoder,**params) # print "banana" except: return None, None session = oauth_service.get_session(access_token) return oauth_service, access_token # Type is either RESOURCES or LINKS def GetResponse(self, url, oauth_service, access_token, type, debug=False): result = self.ngs_request(url, oauth_service, access_token, debug) if debug: print "#########\n\n",result,"\n\n#########" response = {} try: # parse out the response from the server response = self.HandleLinks(result['resource'],type) except ValueError: print "Server replied but reponse is in an unsupported format." sys.exit(1) return response # Formates a lat/lon into one string with 2 decimal places def FormatLocation(self, value): lat = value['latitude'] lon = value['longitude'] if lat != None and lon != None: loc = '%.2f_%.2f'%(float(lat),float(lon)) return lon,lat,loc else: loc = '0_0' return 0,0,loc #Given All samples create a set of unique locations and the sequences that belong to them #Returns a dictionary of this information def CreateLocations(self, samples): idNum = 1 idString = 'Loc_' locations = {} for sample in samples: for key, value in sample.items(): lon,lat,loc = self.FormatLocation(value) id = idString + '%0*d' %(3,idNum) idNum += 1 if loc in locations: locations[loc].append(key) else: locations[loc] = [id, lon, lat, key] return locations def CreateOutText(self, locations, samples): locationText = "" sequenceText = "" locationHeader = "Site ID, Longitude, Latitude\n" sequencesHeader = ["Sequence ID, Site ID "] first = True #first create locations for key, value in locations.items(): locationText = '%s%s, %s, %s\n' %( locationText, value[0], value[1], value[2] ) locationText = locationHeader + locationText #then create sequences for sample in samples: for key, values in sample.items(): seq = [] #Append Sequence ID seq.append(key) #Append Site ID # seq.append('Seq_%0*d' %(3, idNum) ) lon,lat,loc = self.FormatLocation(values) seq.append(locations[loc][0]) for i,j in values.items(): if i == 'links': continue if first: sequencesHeader.append(str(i)) seq.append(str(j).replace(',','|')) first = False text = ','.join(seq) sequenceText = sequenceText + text + '\n' sequenceHeader = ','.join(sequencesHeader) sequenceText = sequenceHeader + '\n' + sequenceText return locationText, sequenceText def OnHelp(self, event): wx.LaunchDefaultBrowser( 'http://kiwi.cs.dal.ca/GenGIS/index.php/Description_of_GenGIS_plugins#MG-RAST_Query' ) # Close the Plugin def OnClose(self, event): if self.login: self.login.Close() event.Skip() # Close the Plugin def OnOK( self, event ): self.Close() # Add Data from Results Table to ID List def OnAdd(self,event): i=0 IDCount = self.m_IDList.GetCount() for index in self.m_Result.GetSelections(): selected = self.m_Result.GetString(index) split = selected.split(": ") if (split[0],split[1]) not in self.selectedTaxon: self.m_IDList.InsertItems(["%s" % selected],IDCount+i) #add study ID and study location self.selectedTaxon.add((split[0],split[1])) i+=1 # Remove Data from ID List def OnRemove(self,event): candidates = sorted(self.m_IDList.GetSelections(),reverse=True) for index in candidates: selected = self.m_IDList.GetString(index) split = selected.split(": ") self.selectedTaxon.remove((split[0],split[1])) self.m_IDList.Delete(index) # Retrieves token from IRIDA API. def AuthorizeToken(self): if self.username == "" or self.password == "": wx.MessageBox("Please enter a username and/or password.") return 0 if self.clientId == "" or self.clientSecret == "": wx.MessageBox("No Client Credentials have been loaded.") return -1 try: self.service, self.token = self.GetToken() if self.service == None or self.token == None: wx.MessageBox("Bad username and/or password.") return 0 except ValueError: wx.MessageBox("Unable to retrieve token from API at this time. Please try again later.") return 0 return 1 def InitializeResults(self): wx.BeginBusyCursor() result = [] links = self.GetResponse(self.baseURL+'projects/', self.service, self.token,'resources') if len(links.keys())==0: wx.MessageBox("No Projects currently stored in IRIDA") else: for key,value in links.items(): str = "%s: %s" %(key,value['projectDescription']) # add mapping for this project self.projectMap[key] = value['identifier'] result.append(str) self.m_Result.InsertItems(result,self.m_Result.GetCount()) wx.EndBusyCursor() def InitializeAnalyses(self): wx.BeginBusyCursor() result = [] links = self.GetResponse(self.baseURL+'analysisSubmissions/', self.service, self.token,'resources') if len(links.keys())==0: wx.MessageBox("No analyses currently stored in IRIDA") else: for key,value in links.items(): str = "%s: %s" %(key,value['label']) # add mapping for this project self.projectMap[key] = value['identifier'] result.append(str) self.m_Result.InsertItems(result,self.m_Result.GetCount()) wx.EndBusyCursor() def OnSearch(self,event): wx.BeginBusyCursor() # Clear the results list projName = self.m_ProjectName.GetValue() if projName not in self.projectMap.keys(): wx.EndBusyCursor() wx.MessageBox("Please enter a valid Project name.") return project = projName if(len(project)==0): wx.MessageBox("You did not enter a taxon name.") else: self.selectedTaxon.clear() self.selectedTaxon.add((project,"dummy value")) self.OnCalculate(wx.EVT_BUTTON) wx.EndBusyCursor() def OnCalculate( self, event): self.RetrieveSamples() # self.RetrievePhylogeny() # def RetrieveSamples(self,event): def RetrieveSamples(self): if(self.selectedTaxon): #index of which taxon is being used index = 0 for proj in self.selectedTaxon: self.m_Progress.WriteText("Retrieving %s...\n" %(proj[0])) project = self.projectMap[proj[0]] # projectURL = '%sprojects/%s' %(self.baseURL,project) projectURL = '%sprojects/%s' %(self.baseURL,3) self.phylo = self.RetrieveKnownPhylogeny(project) # print newick projLink = self.GetResponse(projectURL, self.service, self.token,'links') sampleURL = projLink['project/samples'] samples = self.GetResponse(sampleURL, self.service, self.token, 'resources') # obs is just a list of these samples self.obs.append(samples) self.m_Progress.WriteText("%s samples retrieved.\n" %(len(samples.keys()))) self.m_Progress.WriteText("Done.\n") # def RetrievePhylogeny(self,event): def RetrievePhylogeny(self): if(self.selectedTaxon): #index of which taxon is being used index = 0 for proj in self.selectedTaxon: self.m_Progress.WriteText("Retrieving %s...\n" %(proj[0])) project = self.projectMap[proj[0]] projectURL = '%sanalysisSubmissions/%s' %(self.baseURL,project) print projectURL projLink = self.GetResponse(projectURL, self.service, self.token,'links') analysisURL = projLink['analysis'] print analysisURL # get samples ''' sequenceURL = analysisURL + "/sequenceFiles/pairs" print "pants" sequenceLink = self.GetResponse(projectURL, self.service, self.token, 'response',True) print "sandwich" ''' # get phylogeny links = self.GetResponse(analysisURL, self.service, self.token, 'links') newickURL = links['outputFile/tree'] newick = self.newick_request(newickURL, self.service,self.token,True) # obs is just a list of these samples # self.obs.append(samples) self.m_Progress.WriteText("%s samples retrieved.\n" %(len(samples.keys()))) self.m_Progress.WriteText("Done.\n") def RetrieveKnownPhylogeny(self, identifier): projectURL = '%sanalysisSubmissions/%s' %(self.baseURL,identifier) projLink = self.GetResponse(projectURL, self.service, self.token,'links') analysisURL = projLink['analysis'] # get phylogeny links = self.GetResponse(analysisURL, self.service, self.token, 'links') newickURL = links['outputFile/tree'] newick = self.newick_request(newickURL, self.service,self.token) return newick def OnAddData(self, event): if GenGIS.layerTree.GetNumMapLayers() == 0: wx.MessageBox("This action requires a Map layer. Please load a Map.") return if len(self.obs) > 0: loc = self.CreateLocations(self.obs) locText, seqText = self.CreateOutText(loc,self.obs) locArray = locText.split('\n') seqArray = seqText.split('\n') locArray.pop() seqArray.pop() layerName = "IRIDALayer_%d" % GenGIS.layerTree.GetNumLocationLayers() GenGIS.mainWindow.OpenLocationsCSVFile(locArray, layerName) GenGIS.mainWindow.OpenSequenceCSVFile(seqArray, layerName) print self.phylo self.phylo = self.phylo.replace("reference:0.00000001,","") print self.phylo fh = "phylogeny.nwk" file = open("phylogeny.nwk",'w') file.write(self.phylo) file.close() GenGIS.mainWindow.OpenTreeFile(fh) else: wx.MessageBox("Please make a successful IRIDA query first.") def OnExportData(self,event): if (len(self.obs) > 0): fileTypes = 'Loc and Seq Files (*.csv)|*.csv' dlg = wx.FileDialog(self, "Save plot", "", "", fileTypes, wx.SAVE) if dlg.ShowModal()==wx.ID_OK: filename = dlg.GetFilename() dir = dlg.GetDirectory() file_split = filename.split(".",1) OUTLfile = os.path.join(dir,file_split[0]+"_locs.csv") OUTSfile = os.path.join(dir,file_split[0]+"_seqs.csv") loc = self.CreateLocations(self.obs) locText, seqText = self.CreateOutText(loc,self.obs) self.GBIFGeneric.WRITEEXPORT(OUTLfile , locText ) self.GBIFGeneric.WRITEEXPORT(OUTSfile, seqText ) def SetToken(self,tok): self.token = tok def OnCredentials(self,event): credentials = Credentials(self) credentials.Show() def OnCredentialClose(self,active): # self.credential = active self.clientId = active.GetID() self.clientSecret = active.GetSecret()
class GBIFQuery(GBIFQueryLayout): # Global variables to store queried information __obs__ = [] __selectedTaxon__ = set() __description__ = "" masterKeys = set() def __init__(self, parent=None): MaxLon, MinLon, MaxLat, MinLat = 180, -180, 90, -90 self.GBIFSpecific = GBIFSpecific() self.GBIFGeneric = GBIFGeneric() GBIFQueryLayout.__init__(self, parent) self.SetIcon( wx.Icon(GenGIS.mainWindow.GetExeDir() + "images/CrazyEye.ico", wx.BITMAP_TYPE_ICO)) self.m_Compass.SetIcon( wx.Icon( GenGIS.mainWindow.GetExeDir() + "images/GBIF_compass_small.png", wx.BITMAP_TYPE_PNG)) self.m_Add.SetBitmapLabel( wx.Image( GenGIS.mainWindow.GetExeDir() + "images/green_arrow_down.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Add.SetBitmapHover( wx.Image( GenGIS.mainWindow.GetExeDir() + "images/green_arrow_down_hover.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Remove.SetBitmapLabel( wx.Image(GenGIS.mainWindow.GetExeDir() + "images/red_arrow_up.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Remove.SetBitmapHover( wx.Image( GenGIS.mainWindow.GetExeDir() + "images/red_arrow_up_hover.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.graphicalElementIds = [] self.__selectedTaxon__ = set() self.__obs__ = [] self.m_IDList.Clear() #fix to expand summary box enough to print two lines of text properly self.m_Summary.SetLabel("\n\n") #No Map Data self.m_AddData.Disable() #Map Data if GenGIS.layerTree.GetNumMapLayers() > 0: self.m_AddData.Enable() borders = GenGIS.layerTree.GetMapLayer( 0).GetController().GetMapBorders() #check if geographic coordinates are used or some other measure; only geographic are compatible geographic = GenGIS.StudyController.IsUsingGeographic( GenGIS.study.GetController()) projected = GenGIS.StudyController.IsUsingProjection( GenGIS.study.GetController()) if (not (geographic or projected)): wx.MessageBox( "Geographic coordinates are not being used in the current map file. Only geographic coordinates are compatible with MG-RAST. Geographic range will need to be manually set, and any returned data will not display correctly.", "Warning") self.m_AddData.Disable() self.m_MinLat.SetValue(str(MinLat)) self.m_MaxLat.SetValue(str(MaxLat)) self.m_MinLon.SetValue(str(MinLon)) self.m_MaxLon.SetValue(str(MaxLon)) else: #Text boxes hate non String types. use int to round, and string to make them fit the container # if projected coordinates but not geographic, a conversion may be possible if (projected and not geographic): convTop = self.GBIFGeneric.SpecialUTMConversion( borders.x1, borders.y1) convBottom = self.GBIFGeneric.SpecialUTMConversion( borders.dx, borders.dy) borders.x1 = convTop.easting borders.y1 = convTop.northing borders.dx = convBottom.easting borders.dy = convBottom.northing #limiting borders self.m_MinLat.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MinLat, borders.y1, max))) self.m_MaxLat.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MaxLat, borders.dy, min))) self.m_MinLon.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MinLon, borders.x1, max))) self.m_MaxLon.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MaxLon, borders.dx, min))) # Query GBIF for Taxa in Lat/Lon Boundary def OnSearch(self, event): wx.BeginBusyCursor() # Clear the results list self.m_Result.Clear() taxon = self.m_TaxonName.GetLineText(0) taxon = taxon.split() if (len(taxon) == 0): wx.MessageBox("You did not enter a taxon name.") else: minLatitude = float(self.m_MinLat.GetValue()) maxLatitude = float(self.m_MaxLat.GetValue()) minLongitude = float(self.m_MinLon.GetValue()) maxLongitude = float(self.m_MaxLon.GetValue()) result = self.GBIFSpecific.GETTAXRESULT(taxon, self.m_Result) self.m_Result.InsertItems(result, 0) wx.EndBusyCursor() # Create Sequence and Location files for selected Taxa def OnCalculate(self, event): self.m_Summary.SetLabel("\n") records, distLocations = 0, 0 self.__obs__ = [] self.__conversions__ = [] self.__description__ = "" wx.BeginBusyCursor() if (self.__selectedTaxon__): minLatitude = float(self.m_MinLat.GetValue()) maxLatitude = float(self.m_MaxLat.GetValue()) minLongitude = float(self.m_MinLon.GetValue()) maxLongitude = float(self.m_MaxLon.GetValue()) self.m_Progress.WriteText("Starting...\n") for tax in self.__selectedTaxon__: obs, self.masterKeys, records = self.GBIFSpecific.GETOBSENTIRERANGE( tax[0], minLatitude, maxLatitude, minLongitude, maxLongitude, self.m_Progress) self.__obs__.append(obs) distLocations += len(obs) self.m_Progress.WriteText("Done.\n") else: wx.MessageBox("Please select some Taxa.") summaryText = ("%d records retrieved.\n%d distinct locations." % (records, distLocations)) f = self.m_Summary.GetFont() dc = wx.WindowDC(self.m_Summary) dc.SetFont(f) aSize = dc.GetMultiLineTextExtent(summaryText) aSize = wx.Size(aSize[0], aSize[1]) self.m_Summary.SetSize(aSize) self.m_Summary.SetLabel(summaryText) wx.EndBusyCursor() # Present the number of locations a user is about to query # Used as a check by the user to know they aren't going to produce way too much data. def OnPreCalculate(self, event): wx.BeginBusyCursor() self.m_Progress.WriteText("Retrieving record counts.\n") self.m_Summary.SetLabel("\n") if (self.__selectedTaxon__): count = 0 for tax in self.__selectedTaxon__: count += self.GBIFSpecific.GETCOUNT(tax[1].split(), tax[0], self.m_Progress) self.m_Summary.SetLabel( "There were %d records for the given location." % count) else: wx.MessageBox("Please select some Taxa.") wx.EndBusyCursor() # Redirects User to Wiki page for this plugin def OnHelp(self, event): wx.LaunchDefaultBrowser( 'http://kiwi.cs.dal.ca/GenGIS/index.php/Description_of_GenGIS_plugins#GBIF_Query' ) # Adds Data to GenGIS def OnAddData(self, event): if (len(self.__obs__) > 0): OUTLText, OUTSText = self.GBIFGeneric.GETTEXT( self.__obs__, self.masterKeys) OUTLArray = self.GBIFGeneric.CPPOUT(OUTLText) OUTSArray = self.GBIFGeneric.CPPOUT(OUTSText) OUTLArray.pop() OUTSArray.pop() layerName = "GBIFLayer_%d" % GenGIS.layerTree.GetNumLocationSetLayers( ) GenGIS.mainWindow.OpenLocationsCSVFile(OUTLArray, layerName) GenGIS.mainWindow.OpenSequenceCSVFile(OUTSArray, layerName) #Get the number of last location layer added (the gbif one) numLocationLayers = GenGIS.layerTree.GetNumLocationSetLayers() locationSetLayer = GenGIS.layerTree.GetLocationSetLayer( numLocationLayers - 1) else: wx.MessageBox("Please make a successful GBIF Query first.") # Exports Location and Sequence Data to a location of the users choice def OnExportData(self, event): if (len(self.__obs__) > 0): fileTypes = 'Loc and Seq Files (*.csv)|*.csv' dlg = wx.FileDialog(self, "Save plot", "", "", fileTypes, wx.SAVE) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dir = dlg.GetDirectory() file_split = filename.split(".", 1) #creates the directories OUTLfile = os.path.join(dir, file_split[0] + "_locs.csv") OUTSfile = os.path.join(dir, file_split[0] + "_seqs.csv") OUTLText, OUTSText = self.GBIFGeneric.GETTEXT( self.__obs__, self.masterKeys) self.GBIFGeneric.WRITEEXPORT(OUTLfile, OUTLText) self.GBIFGeneric.WRITEEXPORT(OUTSfile, OUTSText) dlg.Destroy() else: wx.MessageBox("Please make a successful GBIF Query first.") # Add Data from Results Table to ID List def OnAdd(self, event): i = 0 IDCount = self.m_IDList.GetCount() for index in self.m_Result.GetSelections(): selected = self.m_Result.GetString(index) split = selected.split(" | ") if (int(split[0]), split[1]) not in self.__selectedTaxon__: self.m_IDList.InsertItems(["%s" % selected], IDCount + i) self.__selectedTaxon__.add((int(split[0]), split[1])) i += 1 # Remove Data from ID List def OnRemove(self, event): candidates = sorted(self.m_IDList.GetSelections(), reverse=True) for index in candidates: selected = self.m_IDList.GetString(index) split = selected.split(" | ") self.__selectedTaxon__.remove((int(split[0]), split[1])) self.m_IDList.Delete(index) # Close the Plugin def OnClose(self, event): # remove plotted lines for id in self.graphicalElementIds: GenGIS.graphics.RemoveLine(id) GenGIS.viewport.Refresh() event.Skip() # Close the Plugin def OnOK(self, event): self.Close() def OnLatEnter(self, event): str = event.GetString() str2 = re.sub('[^\d\.\-]', '', str) if str2 and str != "-": str3 = float(str2) if str3 > 90: str2 = str2[:-1] elif str3 < -90: str2 = str2[:-1] event.GetClientData().SetValue(str2) event.GetClientData().SetInsertionPoint(len(str2)) def OnLonEnter(self, event): str = event.GetString() str2 = re.sub('[^\d\.\-]', '', str) if str2 and str != "-": str3 = float(str2) if str3 > 180: str2 = str[:-1] elif str3 < -180: str2 = str[:-1] event.GetClientData().SetValue(str2) event.GetClientData().SetInsertionPoint(len(str2))
class MGRastQuery(MGRASTQueryLayout): # Global variables to store queried information __obs__ = [] __selectedTaxon__ = set() __description__ = "" __options__ = "" __metaVals__ = {} __TAXON__ = [ "Domain", "Phylum", "Class", "Order", "Family", "Genus", "Species", "Strain" ] def __init__(self, parent=None): self.__options__ = Options() self.MGRastSpecific = MGRastSpecific() MGRASTQueryLayout.__init__(self, parent) self.GBIFGeneric = GBIFGeneric() self.SetIcon( wx.Icon(GenGIS.mainWindow.GetExeDir() + "images/CrazyEye.ico", wx.BITMAP_TYPE_ICO)) self.m_Add.SetBitmapLabel( wx.Image( GenGIS.mainWindow.GetExeDir() + "images/green_arrow_down.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Add.SetBitmapHover( wx.Image( GenGIS.mainWindow.GetExeDir() + "images/green_arrow_down_hover.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Remove.SetBitmapLabel( wx.Image(GenGIS.mainWindow.GetExeDir() + "images/red_arrow_up.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Remove.SetBitmapHover( wx.Image( GenGIS.mainWindow.GetExeDir() + "images/red_arrow_up_hover.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.m_Compass.SetIcon( wx.Icon( GenGIS.mainWindow.GetExeDir() + "images/GBIF_compass_small.png", wx.BITMAP_TYPE_PNG)) MaxLon, MinLon, MaxLat, MinLat = 180, -180, 90, -90 self.m_IDList.Clear() #fix to expand summary box enough to print two lines of text properly self.m_Summary.SetLabel("\n\n") #Map Data if GenGIS.layerTree.GetNumMapLayers() > 0: self.m_AddData.Enable() borders = GenGIS.layerTree.GetMapLayer( 0).GetController().GetMapBorders() #check if geographic coordinates are used or some other measure; only geographic are compatible geographic = GenGIS.StudyController.IsUsingGeographic( GenGIS.study.GetController()) projected = GenGIS.StudyController.IsUsingProjection( GenGIS.study.GetController()) if (not (geographic or projected)): wx.MessageBox( "Geographic coordinates are not being used in the current map file. Only geographic coordinates are compatible with MG-RAST. Geographic range will need to be manually set, and any returned data will not display correctly.", "Warning") self.m_AddData.Disable() self.m_MinLat.SetValue(str(MinLat)) self.m_MaxLat.SetValue(str(MaxLat)) self.m_MinLon.SetValue(str(MinLon)) self.m_MaxLon.SetValue(str(MaxLon)) else: #Text boxes hate non String types. use int to round, and string to make them fit the container # if projected coordinates but not geographic, a conversion may be possible if (projected and not geographic): convTop = self.GBIFGeneric.SpecialUTMConversion( borders.x1, borders.y1) convBottom = self.GBIFGeneric.SpecialUTMConversion( borders.dx, borders.dy) borders.x1 = convTop.easting borders.y1 = convTop.northing borders.dx = convBottom.easting borders.dy = convBottom.northing #limiting borders self.m_MinLat.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MinLat, borders.y1, max))) self.m_MaxLat.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MaxLat, borders.dy, min))) self.m_MinLon.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MinLon, borders.x1, max))) self.m_MaxLon.SetValue( str("%.1f" % self.GBIFGeneric.BorderTest(MaxLon, borders.dx, min))) # Query GBIF for Taxa in Lat/Lon Boundary def OnSearch(self, event): wx.BeginBusyCursor() # Clear the results list self.m_Result.Clear() searchType = self.__options__.GetSearchType() taxon = self.m_TaxonName.GetLineText(0) taxon = taxon.split() if (len(taxon) == 0): wx.MessageBox("You did not enter a taxon name.") else: minLatitude = float(self.m_MinLat.GetValue()) maxLatitude = float(self.m_MaxLat.GetValue()) minLongitude = float(self.m_MinLon.GetValue()) maxLongitude = float(self.m_MaxLon.GetValue()) if searchType == "study": self.__selectedTaxon__.clear() # test data for multiple study search mgm4440037.3 mgm4440055.3 mgm4440064.3 for tax in taxon: self.__selectedTaxon__.add(("dummy value", tax)) self.OnCalculate(wx.EVT_BUTTON) else: matches = self.MGRastSpecific.GETTAXRESULT( taxon, searchType, minLatitude, maxLatitude, minLongitude, maxLongitude, self.m_Summary) if matches: self.m_Result.InsertItems(matches, 0) wx.EndBusyCursor() # Create Sequence and Location files for selected Taxa ###################### # # CAN NOT PERFORM MORE THAN ONE QUERY PER SECOND # ###################### def OnCalculate(self, event): self.MGRastSpecific.RESETSEQUENCE() self.__obs__ = [] self.__metaVals__ = {} sequence = {} self.m_Summary.SetLabel("\n") records, distLocations = 0, 0 searchType = self.__options__.GetSearchType() additFields = "%s%s%s%s%s%s%s" % ( self.__options__.GetFilterLevel(), self.__options__.GetFilterSource(), self.__options__.GetGroupLevel(), self.__options__.GetHitType(), self.__options__.GetIdentity(), self.__options__.GetLength(), self.__options__.GetSource()) if (self.__selectedTaxon__): self.m_Progress.WriteText("Starting...\n") #index of which taxon is being used index = 0 for tax in self.__selectedTaxon__: startTime = time.time() obs, metaVals, taxonLength = self.MGRastSpecific.GETOBS( tax[1], searchType, additFields, self.m_Progress) # Some sort of error occured trying to get that object, skip to next one if not obs: self.SetFocus() continue taxonomy = [] for i in range(0, taxonLength): if i < len(self.__TAXON__): taxonomy.append(self.__TAXON__[i]) else: taxonomy[i].append("Level_%s" % i) self.__TAXON__ = taxonomy if obs: self.__obs__.append(obs) if sequence: self.__sequences__.append(sequence) # add all unique key/val pairs from json files for key, value in metaVals.iteritems(): if key in self.__metaVals__: self.__metaVals__[key][index] = value else: list = [''] * len(self.__selectedTaxon__) list[index] = value self.__metaVals__[key] = list index += 1 if (time.time() - startTime) < 1: sleep.time(1) # Now query again for the Sequence to that study if self.__options__.GetSequence(): fileTypes = 'Sequence data files (*.fasta)|*.fasta' dlg = wx.FileDialog(self, "Save plot", "", "", fileTypes, wx.SAVE) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dir = dlg.GetDirectory() file_split = filename.split(".", 1) outFile = ("%s/%s_sequenceData.fasta.gz" % (dir, file_split[0])) self.MGRastSpecific.GETSEQUENCES(tax[1], self.m_Progress, outFile) else: wx.MessageBox("Please select some Taxa.") self.m_Progress.WriteText("Done\n") # Redirects User to Wiki page for this plugin def OnHelp(self, event): wx.LaunchDefaultBrowser( 'http://kiwi.cs.dal.ca/GenGIS/index.php/Description_of_GenGIS_plugins#MG-RAST_Query' ) # Adds Data to GenGIS def OnAddData(self, event): # check required data has been loaded if GenGIS.layerTree.GetNumMapLayers() == 0: wx.MessageBox( "This action requires a Map layer. Please load a Map.") self.Close() return taxonLevels = ','.join(str(i) for i in self.__TAXON__) if (len(self.__obs__) > 0): OUTLText, OUTSText = self.MGRastSpecific.GETTEXT( self.__obs__, self.__metaVals__) OUTLArray = self.GBIFGeneric.CPPOUT(OUTLText) OUTSArray = self.GBIFGeneric.CPPOUT(OUTSText) metKey = ','.join(sorted(self.__metaVals__.keys())) OUTLArray.insert(0, "Site ID,Latitude,Longitude,Cell ID,%s" % metKey) OUTSArray.insert( 0, "Sequence ID,Site ID,CellLat,CellLong,Richness,%s,Taxonomy" % taxonLevels) OUTLArray.pop() OUTSArray.pop() layerName = "MGRASTLayer_%d" % GenGIS.layerTree.GetNumLocationLayers( ) GenGIS.mainWindow.OpenLocationsCSVFile(OUTLArray, layerName) GenGIS.mainWindow.OpenSequenceCSVFile(OUTSArray, layerName) #Get the number of last location layer added (the gbif one) numLocationLayers = GenGIS.layerTree.GetNumLocationSetLayers() locationSetLayer = GenGIS.layerTree.GetLocationSetLayer( numLocationLayers - 1) # locationSetLayer.SetDescription(self.__description__) else: wx.MessageBox("Please make a successful MG-RAST Query first.") # Exports Location and Sequence Data to a location of the users choice def OnExportData(self, event): if (len(self.__obs__) > 0): taxonLevels = ','.join(str(i) for i in self.__TAXON__) fileTypes = 'Loc and Seq Files (*.csv)|*.csv' dlg = wx.FileDialog(self, "Save plot", "", "", fileTypes, wx.SAVE) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dir = dlg.GetDirectory() file_split = filename.split(".", 1) #creates the directories OUTLfile = os.path.join(dir, file_split[0] + "_locs.csv") OUTSfile = os.path.join(dir, file_split[0] + "_seqs.csv") OUTLText, OUTSText = self.MGRastSpecific.GETTEXT( self.__obs__, self.__metaVals__) # metKey = ','.join(str(x) for x in self.__metaKeys__) metKey = ','.join(sorted(self.__metaVals__.keys())) # print metKey self.GBIFGeneric.WRITEEXPORT( OUTLfile, OUTLText, "Site ID,Latitude,Longitude,Cell ID,%s\n" % metKey) self.GBIFGeneric.WRITEEXPORT( OUTSfile, OUTSText, "Sequence ID,Site ID,CellLat,CellLong,Richness,%s,Taxonomy\n" % taxonLevels) # if self.__options__.GetSequence(): # self.MGRastSpecific.WRITESEQUENCES(dir,file_split[0],self.__sequences__) dlg.Destroy() else: wx.MessageBox("Please make a successful MG-RAST Query first.") # Add Data from Results Table to ID List def OnAdd(self, event): i = 0 IDCount = self.m_IDList.GetCount() for index in self.m_Result.GetSelections(): selected = self.m_Result.GetString(index) split = selected.split(" | ") if (split[0], split[1]) not in self.__selectedTaxon__: self.m_IDList.InsertItems(["%s" % selected], IDCount + i) #add study ID and study location self.__selectedTaxon__.add((split[0], split[1])) i += 1 # Remove Data from ID List def OnRemove(self, event): candidates = sorted(self.m_IDList.GetSelections(), reverse=True) for index in candidates: selected = self.m_IDList.GetString(index) split = selected.split(" | ") self.__selectedTaxon__.remove((split[0], split[1])) self.m_IDList.Delete(index) # Close the Plugin def OnClose(self, event): self.__options__.Close() event.Skip() # Close the Plugin def OnOK(self, event): self.Close() self.__options__.Close() def OnLatEnter(self, event): str = event.GetString() str2 = re.sub('[^\d\.\-]', '', str) if str2 and str != "-": str3 = float(str2) if str3 > 90: str2 = str2[:-1] elif str3 < -90: str2 = str2[:-1] event.GetClientData().SetValue(str2) event.GetClientData().SetInsertionPoint(len(str2)) def OnLonEnter(self, event): str = event.GetString() str2 = re.sub('[^\d\.\-]', '', str) if str2 and str != "-": str3 = float(str2) if str3 > 180: str2 = str[:-1] elif str3 < -180: str2 = str[:-1] event.GetClientData().SetValue(str2) event.GetClientData().SetInsertionPoint(len(str2)) def OnOptions(self, event): self.__options__.Show()