Пример #1
0
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()
		
Пример #2
0
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))
Пример #3
0
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()