<commit_before>from decimal import *
from functions import spinMatchFinder, levelExtract, NUCIDgen, Correct_Uncertainty
from uncertainty import multuncert

class data:##This is the main data class.
    def __init__(self,ENSDF,ISOvar,option,betaVar,energyLimit = 999999999):
        ###maybe get rid of option, find out how energy limit and max spin are used

        ##Initialize Parameters
        self.data = []
        self.name = ISOvar
        self.op = option
        self.decay = betaVar

        ## nucID is what is compared to the first 6 characters of the line to find the correct data
        nucID=self.name.upper()
        if self.op == 'two':#FIXME Decay Data setup
            parent = ''
            daughter = ''
            Avalue = ''
            ## assign Avalue and parent values
            for char in nucID:
                if char.isnumeric():
                    Avalue = Avalue + char
                elif char.isalpha():
                    parent = parent + char

            perTable = open("ElementList.txt","r")
            periodicTable = perTable.readline()
            periodicTable = periodicTable.split(',')
            periodicTable[-1] = periodicTable[-1][:-1]
            ## Assign daughter nucleus
            for item in periodicTable:
                if item.upper() == parent:
                    index = periodicTable.index(item)
                    if self.decay == "B+":
                        daughter = periodicTable[index-1].upper()
                        decayLabel = 'E'
                    elif self.decay == "B-":
                        daughter = periodicTable[index+1].upper()
                        decayLabel = 'B'
            parent = Avalue+parent
            daughter = NUCIDgen(Avalue+daughter)
            #print('Parent: '+ parent)
            #print('Daughter: '+daughter)
            nucID = daughter
        else:
            nucID = NUCIDgen(nucID)

        ##open the appropriate ensdf file
        self.f = open("Data/"+str(ENSDF),'rU')

        linecount = 0 ## printing linecount can help locate problem-causing lines in the ensdf file
        desiredData = False
        adoptedGammas = True
        needDecayRec = False
        need_ss_info = False

        for line in self.f:
            linecount+=1
            ## The line parsing algorithm is derived from the labeling system of the ensdf files
            ## See the endsf manual, pg. 22, for more information about how the lines of data are organized

            ## Check if line is an End Record (end of a data set)
            if (desiredData and line[0:6].strip() == ''):
                if option == 'two':
                    desiredData = False
                    if adoptedGammas: ## End of Adopted Gammas Dataset
                        adoptedGammas = False
                        ## adoptedLevelRec is used when reading the Decay Data Set
                        adoptedLevelRec = self.data[:]
                        self.data = []
                    continue
                else: ## Option 1 & 3
                    break

            ## dsid is used in identifying decay data
            dsid = line[9:39].split(' ')

            ## Locate the level records in the ADOPTED GAMMAS Dataset
            ## i.e. identifies which lines in the data file have relevant data
            if (adoptedGammas and line[6:8]==' L' and line[0:6]==nucID):
                #print(linecount,line[:-1])
                ## set desiredData bool so the program wil exit after reading adopted data
                desiredData = True
                ##[name,energy,jpi,uncert,hlife,dhlife] <- output of levelExtract
                recordData = levelExtract(line,self.data)
                ## levelExtract passes error codes for continue
                if recordData == [-1]:
                    continue
                if(float(recordData[1])<=energyLimit):
                    ## include the data
                    self.data.append(recordData)
                else:
                    if option == 'two':
                        continue
                    else:
                        break
                ## If no ground state energy is given, move on to the next isotope
                if recordData[2]=='X':
                    print ('Missing ground state energy data for '+nucID)
                    break

            ## Get Decay Data ##
            if self.op == "two" and not adoptedGammas:

                ## Locate identification record for the decay dataset
                if (line[0:6] == daughter and line[6:9] == '   ' and dsid[0] == parent):
                    desiredData = True
                if desiredData == True:

                    ## Locate Parent Record and retrieve data
                    if (line[0:6] == NUCIDgen(parent) and line[6:8]==' P'):
                        recordData = levelExtract(line,self.data)
                        if recordData == [-1]:
                            continue
                        if(float(recordData[1])<=energyLimit):
                            self.data.append(recordData)

                    ## Locate the Normalization record for scaling branching ratios
                    #FIXME get error & propagate
                    #FIXME make error magnitude assignment an importable function
                    if (line[0:6] == daughter and line[6:8] == ' N'):
                        ## See ensdf manual for more information on what these terms are (pg. 18)
                        BR = line[31:39].strip()
                        dBR = line[39:41].strip()
                        NB = line[41:49].strip()
                        dNB = line[49:55].strip()

                        if BR == '':
                            BR = '1'
                        if NB == '':
                            NB = '1'
                        if dBR == '':
                            dBR = '0'
                        else:
                            dBR = Correct_Uncertainty(BR,dBR)
                        if dNB == '':
                            dNB = '0'
                        else:
                            dNB = Correct_Uncertainty(NB,dNB)

                        scale_factor = float(NB)*float(BR)
                        d_scale_factor = multuncert(float(NB),float(BR),float(dNB),float(dNB))

                    ## Locate the PN record to use instead of N record scaling
                    ## the N rec is only used if PN rec is empty
                    #FIXME get error & propagate
                    if (line[0:6] == daughter and line[6:8] == 'PN'):
                        NBBR = line[41:49].strip()
                        dNBBR = line[49:55].strip()
                        if not NBBR == '':
                            if dNBBR == '':
                                ## Use d_scale_factor from N record
                                pass
                            else:
                                d_scale_factor = ScaleUncert(NBBR,dNBBR)

                            scale_factor = float(NBBR)
                        ## Else: use scale_factor from N record

                    ## Locate daughter Level Record
                    elif (line[0:6] == daughter and line[6:8]==' L'):
                        ## Get data from adoptedLevelRec
                        recordData = levelExtract(line,self.data)
                        if recordData == [-1]:
                            continue
                        if(float(recordData[1])<=energyLimit):
                            dataMatch = False
                            errorList = []
                            ## Frequently in the Decay Data Sets, the level records for the daughter isomers lack half life data, so that state's level record from the Adopted Gammas Data Set is used instead (all of the Gamma Level records are constained in adoptedLevelRec).

                            ## Find matching Adopted Gamma record
                            for record in adoptedLevelRec:
                                if Decimal(record[1]) == Decimal(recordData[1]):
                                    matchedRecord = record[:] ##Necessary string copy
                                    self.data.append(matchedRecord)
                                    dataMatch = True
                                    break
                                ## Sometimes the energy of a state differs between the Decay Data Set and the Adopted Data Set. A percent error (of energy) calculation is used to determine the closest Adopted Data Set level record for a given Decay Data Set level record.
                                else:
                                    errorPercent = abs((Decimal(record[1])-Decimal(recordData[1]))/Decimal(recordData[1])*Decimal('100'))
                                    errorList.append(errorPercent)
                            if not dataMatch:
                                ## MAXERROR is the maximum percent error with which a Decay Data Set state can be matched to an Adopted Gammas state.
                                MAXERROR = 1
                                minIndex = errorList.index(min(errorList))
                                if errorList[minIndex] < MAXERROR:
                                    #print(adoptedLevelRec[minIndex])
                                    minRec = adoptedLevelRec[minIndex]
                                    closestRec = minRec[:] ##Necessary string copy
                                    self.data.append(closestRec)
                                    ## Inform the user that a state has been imperfectly matched
                                    #print(recordData[0]+' state at '+recordData[1]+' keV matched to adopted level at '+adoptedLevelRec[minIndex][1]+' keV w/ error of '+str(round(errorList[minIndex],4))+'%.')
                                ## Case where the nearest Adopted Data Set level record is not within MAXERROR percent of the Decay Data Set level record.
                                else:
                                    #print('No adopted record found for '+recordData[0]+' at '+recordData[1]+' keV with under '+str(MAXERROR)+'% error.')
                                    self.data.append(recordData)
                            if needDecayRec == True:
                                ##no Decay record for previous daughter Level rec
                                self.data[-2].extend(('0','0'))
                            needDecayRec = True
                            errorList = []
                        else:
                            continue
                    ## Identify decay record
                    elif(needDecayRec and line[0:6] == daughter and line[6:8]==' '+decayLabel):
                        ## Variables named *I are branching intensities
                        betaI = line[21:29].strip() ##Beta decay branching intensity
                        dbetaI = line[29:31].strip()
                        ## give uncertainty correct magnitude
                        if any (char.isalpha() for char in dbetaI):
                            pass
                        elif dbetaI == '':
                            pass
                        elif ('.' in betaI):
                            dbetaI = str(float(Correct_Uncertainty(betaI,dbetaI))*scale_factor)

                        ecI = line[31:39].strip() ##Electron Capture branching intensity
                        decI = line[39:41].strip()

                        ## give uncertainty correct magnitude
                        if any (char.isalpha() for char in decI):
                            pass
                        elif decI == '':
                            pass
                        elif ('.' in ecI):
                            decI = str(float(Correct_Uncertainty(ecI,decI))*scale_factor)

                        ## get total branching intensity
                        if ecI == '' and betaI == '':
                            totBranchI = ''
                        elif ecI == '':
                            totBranchI = str(float(betaI)*scale_factor)
                        elif betaI == '':
                            totBranchI = str(float(ecI)*scale_factor)
                        else:
                            totBranchI = str((float(betaI) + float(ecI))*scale_factor)
                        needDecayRec = False
                        self.data[-1].append(totBranchI)

                        ## Append ecI/(ecI+B+)
                        if ecI == '':
                            ecI = 0
                            self.data[-1].append('0')
                        else:
                            self.data[-1].append(str(float(ecI)*scale_factor))

                        ### Subshell Data ###
                        if not ecI == '': #FIXME
                            need_ss_info = True
                    '''
                    ## Subshell Data Acquisition
                    elif(need_ss_info and line[0:5] == daughter[:-1] and line[5].isalnum() and line[6:8]==' '+decayLabel):
                        ## (Isotope, energy, t1/2, dt1/2, CK%, CL%, CM%) #0145
                        ss_data = [self.data[-1][i] for i in [0,1,4,5]]
                        print('%s Energy: %s  t1/2: %s  dt1/2: %s  ' % tuple(ss_data))
                        if any(cx in line for cx in ['CK','CL','CM']):
                            print(line[9:])
                            need_ss_info = False
                    '''

    def export(self,fExtOption = '.dat',extraTitleText = ''):
#            if(fExtOption==".dat"or fExtOption=="_Fil.dat"):##To make data files for use in gnuplot and plt file.
            fileName=str(self.name)+extraTitleText+fExtOption##creates filename
            fileName="Output/" + "gnuPlot/"+fileName.replace('/','_')
            datFile = open(fileName,'wb')##Creates a file with a valid file name.
            for i in range(len(self.data)):
                lineToWrite = str(self.data[i][0])
                for j in range(1,len(self.data[i])):
                    lineToWrite = lineToWrite + ';' +str(self.data[i][j])
                lineToWrite = lineToWrite + '\n'
                datFile.write(str.encode(lineToWrite))

    ## Filters by desired spin states, if given
    def filterData(self,userInput,UI=False):
        ## no spin input
        if (userInput == ''):
            #print(self.data)
            if (not self.data):
                if(UI):
                    pass
                    ## Prints a statement telling user than no file was found
                    #print("Warning:No data filtered/selected for "+ self.name +".")
                self.data=[['NULL',0.0,"--",0.0,0.0,[0.0]]]##Enters a dummy entry to file with something.

        ## Filter by spin states
        else:
            if (self.data): ## If self.data has data in it
                newData = []
                groundSt = self.data[0]
                for i in range(1,len(self.data)):
                    #print(self.name,self.data[i])
                    ## The spinMatchFinder will identify if the state is the desired spin
                    if any(spinMatchFinder(wantedString, self.data[i][2]) for wantedString in userInput.split(',')):
                        newData.append(self.data[i])
                self.data=newData[:]##changes data to the new data.
                if (self.data):
                    self.data.insert(0,groundSt)
                else:

                    if any(spinMatchFinder(wantedString,groundSt[2])for wantedString in userInput.split(',')):
                        self.data.append(groundSt)
                    else:
                        self.data = [['NULL',0.0,"--",0.0,0.0,0.0]]##Enters a dummy entry to file with something.

            else: ## If self.data is empty
                if(UI):
                    ## Prints a statement telling user than no file was found
                    pass
                    #print("Warning:No data filtered/selected for "+ self.name +".")#Prints a statement telling user than no file was found
                self.data=[['NULL',0.0,"--",0.0,0.0,0.0]]##Enters a dummy entry to file with something.

<commit_msg>EC uncert written to file<commit_after>from decimal import *
from functions import spinMatchFinder, levelExtract, NUCIDgen, Correct_Uncertainty
from uncertainty import multuncert

class data:##This is the main data class.
    def __init__(self,ENSDF,ISOvar,option,betaVar,energyLimit = 999999999):
        ###maybe get rid of option, find out how energy limit and max spin are used

        ##Initialize Parameters
        self.data = []
        self.name = ISOvar
        self.op = option
        self.decay = betaVar

        ## nucID is what is compared to the first 6 characters of the line to find the correct data
        nucID=self.name.upper()
        if self.op == 'two':#FIXME Decay Data setup
            parent = ''
            daughter = ''
            Avalue = ''
            ## assign Avalue and parent values
            for char in nucID:
                if char.isnumeric():
                    Avalue = Avalue + char
                elif char.isalpha():
                    parent = parent + char

            perTable = open("ElementList.txt","r")
            periodicTable = perTable.readline()
            periodicTable = periodicTable.split(',')
            periodicTable[-1] = periodicTable[-1][:-1]
            ## Assign daughter nucleus
            for item in periodicTable:
                if item.upper() == parent:
                    index = periodicTable.index(item)
                    if self.decay == "B+":
                        daughter = periodicTable[index-1].upper()
                        decayLabel = 'E'
                    elif self.decay == "B-":
                        daughter = periodicTable[index+1].upper()
                        decayLabel = 'B'
            parent = Avalue+parent
            daughter = NUCIDgen(Avalue+daughter)
            #print('Parent: '+ parent)
            #print('Daughter: '+daughter)
            nucID = daughter
        else:
            nucID = NUCIDgen(nucID)

        ##open the appropriate ensdf file
        self.f = open("Data/"+str(ENSDF),'rU')

        linecount = 0 ## printing linecount can help locate problem-causing lines in the ensdf file
        desiredData = False
        adoptedGammas = True
        needDecayRec = False
        need_ss_info = False

        for line in self.f:
            linecount+=1
            ## The line parsing algorithm is derived from the labeling system of the ensdf files
            ## See the endsf manual, pg. 22, for more information about how the lines of data are organized

            ## Check if line is an End Record (end of a data set)
            if (desiredData and line[0:6].strip() == ''):
                if option == 'two':
                    desiredData = False
                    if adoptedGammas: ## End of Adopted Gammas Dataset
                        adoptedGammas = False
                        ## adoptedLevelRec is used when reading the Decay Data Set
                        adoptedLevelRec = self.data[:]
                        self.data = []
                    continue
                else: ## Option 1 & 3
                    break

            ## dsid is used in identifying decay data
            dsid = line[9:39].split(' ')

            ## Locate the level records in the ADOPTED GAMMAS Dataset
            ## i.e. identifies which lines in the data file have relevant data
            if (adoptedGammas and line[6:8]==' L' and line[0:6]==nucID):
                #print(linecount,line[:-1])
                ## set desiredData bool so the program wil exit after reading adopted data
                desiredData = True
                ##[name,energy,jpi,uncert,hlife,dhlife] <- output of levelExtract
                recordData = levelExtract(line,self.data)
                ## levelExtract passes error codes for continue
                if recordData == [-1]:
                    continue
                if(float(recordData[1])<=energyLimit):
                    ## include the data
                    self.data.append(recordData)
                else:
                    if option == 'two':
                        continue
                    else:
                        break
                ## If no ground state energy is given, move on to the next isotope
                if recordData[2]=='X':
                    print ('Missing ground state energy data for '+nucID)
                    break

            ## Get Decay Data ##
            if self.op == "two" and not adoptedGammas:

                ## Locate identification record for the decay dataset
                if (line[0:6] == daughter and line[6:9] == '   ' and dsid[0] == parent):
                    desiredData = True
                if desiredData == True:

                    ## Locate Parent Record and retrieve data
                    if (line[0:6] == NUCIDgen(parent) and line[6:8]==' P'):
                        recordData = levelExtract(line,self.data)
                        if recordData == [-1]:
                            continue
                        if(float(recordData[1])<=energyLimit):
                            self.data.append(recordData)

                    ## Locate the Normalization record for scaling branching ratios
                    #FIXME get error & propagate
                    #FIXME make error magnitude assignment an importable function
                    if (line[0:6] == daughter and line[6:8] == ' N'):
                        ## See ensdf manual for more information on what these terms are (pg. 18)
                        BR = line[31:39].strip()
                        dBR = line[39:41].strip()
                        NB = line[41:49].strip()
                        dNB = line[49:55].strip()

                        if BR == '':
                            BR = '1'
                        if NB == '':
                            NB = '1'
                        if dBR == '':
                            dBR = '0'
                        else:
                            dBR = Correct_Uncertainty(BR,dBR)
                        if dNB == '':
                            dNB = '0'
                        else:
                            dNB = Correct_Uncertainty(NB,dNB)

                        scale_factor = float(NB)*float(BR)
                        d_scale_factor = multuncert(float(NB),float(BR),float(dNB),float(dNB))

                    ## Locate the PN record to use instead of N record scaling
                    ## the N rec is only used if PN rec is empty
                    #FIXME get error & propagate
                    if (line[0:6] == daughter and line[6:8] == 'PN'):
                        NBBR = line[41:49].strip()
                        dNBBR = line[49:55].strip()
                        if not NBBR == '':
                            if dNBBR == '':
                                ## Use d_scale_factor from N record
                                pass
                            else:
                                d_scale_factor = ScaleUncert(NBBR,dNBBR)

                            scale_factor = float(NBBR)
                        ## Else: use scale_factor from N record

                    ## Locate daughter Level Record
                    elif (line[0:6] == daughter and line[6:8]==' L'):
                        ## Get data from adoptedLevelRec
                        recordData = levelExtract(line,self.data)
                        if recordData == [-1]:
                            continue
                        if(float(recordData[1])<=energyLimit):
                            dataMatch = False
                            errorList = []
                            ## Frequently in the Decay Data Sets, the level records for the daughter isomers lack half life data, so that state's level record from the Adopted Gammas Data Set is used instead (all of the Gamma Level records are constained in adoptedLevelRec).

                            ## Find matching Adopted Gamma record
                            for record in adoptedLevelRec:
                                if Decimal(record[1]) == Decimal(recordData[1]):
                                    matchedRecord = record[:] ##Necessary string copy
                                    self.data.append(matchedRecord)
                                    dataMatch = True
                                    break
                                ## Sometimes the energy of a state differs between the Decay Data Set and the Adopted Data Set. A percent error (of energy) calculation is used to determine the closest Adopted Data Set level record for a given Decay Data Set level record.
                                else:
                                    errorPercent = abs((Decimal(record[1])-Decimal(recordData[1]))/Decimal(recordData[1])*Decimal('100'))
                                    errorList.append(errorPercent)
                            if not dataMatch:
                                ## MAXERROR is the maximum percent error with which a Decay Data Set state can be matched to an Adopted Gammas state.
                                MAXERROR = 1
                                minIndex = errorList.index(min(errorList))
                                if errorList[minIndex] < MAXERROR:
                                    minRec = adoptedLevelRec[minIndex]
                                    closestRec = minRec[:] ##Necessary string copy
                                    self.data.append(closestRec)
                                    ## Inform the user that a state has been imperfectly matched
                                    #print(recordData[0]+' state at '+recordData[1]+' keV matched to adopted level at '+adoptedLevelRec[minIndex][1]+' keV w/ error of '+str(round(errorList[minIndex],4))+'%.')
                                ## Case where the nearest Adopted Data Set level record is not within MAXERROR percent of the Decay Data Set level record.
                                else:
                                    #print('No adopted record found for '+recordData[0]+' at '+recordData[1]+' keV with under '+str(MAXERROR)+'% error.')
                                    self.data.append(recordData)
                            if needDecayRec == True:
                                ##no Decay record for previous daughter Level rec
                                self.data[-2].extend(('0','0','0'))
                            needDecayRec = True
                            errorList = []
                        else:
                            continue
                    ## Identify decay record
                    elif(needDecayRec and line[0:6] == daughter and line[6:8]==' '+decayLabel):
                        ## Variables named *I are branching intensities
                        betaI = line[21:29].strip() ##Beta decay branching intensity
                        dbetaI = line[29:31].strip()
                        ## give uncertainty correct magnitude
                        if any (char.isalpha() for char in dbetaI):
                            pass
                        elif dbetaI == '':
                            pass
                        elif ('.' in betaI):
                            dbetaI = str(float(Correct_Uncertainty(betaI,dbetaI))*scale_factor)

                        ecI = line[31:39].strip() ##Electron Capture branching intensity
                        decI = line[39:41].strip()

                        ## give uncertainty correct magnitude
                        if any (char.isalpha() for char in decI):
                            pass
                        elif decI == '':
                            pass
                        elif ('.' in ecI):
                            decI = str(float(Correct_Uncertainty(ecI,decI))*scale_factor)

                        ## get total branching intensity
                        if ecI == '' and betaI == '':
                            totBranchI = ''
                        elif ecI == '':
                            totBranchI = str(float(betaI)*scale_factor)
                        elif betaI == '':
                            totBranchI = str(float(ecI)*scale_factor)
                        else:
                            totBranchI = str((float(betaI) + float(ecI))*scale_factor)
                        needDecayRec = False
                        self.data[-1].append(totBranchI)

                        ## Append ecI/(ecI+B+)
                        if ecI == '':
                            ecI = 0
                            self.data[-1].extend(('0','0'))
                        else:
                            if any(char.isalpha() for char in decI):
                                ecI_error = decI
                            else:
                                ecI_error = multuncert(float(ecI), scale_factor, float(decI),d_scale_factor)
                            ## append net ecI ratio and uncertainty
                            self.data[-1].extend((str(float(ecI)*scale_factor),str(ecI_error)))

                        ### Subshell Data ###
                        if not ecI == '': #FIXME
                            need_ss_info = True
                    '''
                    ## Subshell Data Acquisition
                    elif(need_ss_info and line[0:5] == daughter[:-1] and line[5].isalnum() and line[6:8]==' '+decayLabel):
                        ## (Isotope, energy, t1/2, dt1/2, CK%, CL%, CM%) #0145
                        ss_data = [self.data[-1][i] for i in [0,1,4,5]]
                        print('%s Energy: %s  t1/2: %s  dt1/2: %s  ' % tuple(ss_data))
                        if any(cx in line for cx in ['CK','CL','CM']):
                            print(line[9:])
                            need_ss_info = False
                    '''

    def export(self,fExtOption = '.dat',extraTitleText = ''):
#            if(fExtOption==".dat"or fExtOption=="_Fil.dat"):##To make data files for use in gnuplot and plt file.
            fileName=str(self.name)+extraTitleText+fExtOption##creates filename
            fileName="Output/" + "gnuPlot/"+fileName.replace('/','_')
            datFile = open(fileName,'wb')##Creates a file with a valid file name.
            for i in range(len(self.data)):
                lineToWrite = str(self.data[i][0])
                for j in range(1,len(self.data[i])):
                    lineToWrite = lineToWrite + ';' +str(self.data[i][j])
                lineToWrite = lineToWrite + '\n'
                datFile.write(str.encode(lineToWrite))

    ## Filters by desired spin states, if given
    def filterData(self,userInput,UI=False):
        ## no spin input
        if (userInput == ''):
            #print(self.data)
            if (not self.data):
                if(UI):
                    pass
                    ## Prints a statement telling user than no file was found
                    #print("Warning:No data filtered/selected for "+ self.name +".")
                self.data=[['NULL',0.0,"--",0.0,0.0,[0.0]]]##Enters a dummy entry to file with something.

        ## Filter by spin states
        else:
            if (self.data): ## If self.data has data in it
                newData = []
                groundSt = self.data[0]
                for i in range(1,len(self.data)):
                    #print(self.name,self.data[i])
                    ## The spinMatchFinder will identify if the state is the desired spin
                    if any(spinMatchFinder(wantedString, self.data[i][2]) for wantedString in userInput.split(',')):
                        newData.append(self.data[i])
                self.data=newData[:]##changes data to the new data.
                if (self.data):
                    self.data.insert(0,groundSt)
                else:

                    if any(spinMatchFinder(wantedString,groundSt[2])for wantedString in userInput.split(',')):
                        self.data.append(groundSt)
                    else:
                        self.data = [['NULL',0.0,"--",0.0,0.0,0.0]]##Enters a dummy entry to file with something.

            else: ## If self.data is empty
                if(UI):
                    ## Prints a statement telling user than no file was found
                    pass
                    #print("Warning:No data filtered/selected for "+ self.name +".")#Prints a statement telling user than no file was found
                self.data=[['NULL',0.0,"--",0.0,0.0,0.0]]##Enters a dummy entry to file with something.

<|endoftext|>


<commit_before>from ExifTags import TAGS
import os, Image

supported_exiftags = [
    "ImageWidth",
    "ImageLength",
    "BitsPerSample",
    "Compression",
    "PhotometricInterpretation",
    "ImageDescription",
    "Make",
    "Model",
    "StripOffsets",
    "Orientation",
    "SamplesPerPixel",
    "RowsPerStrip",
    "StripByteConunts",
    "XResolution",
    "YResolution",
    "PlanarConfiguration",
    "ResolutionUnit",
    "TransferFunction",
    "Software",
    "DateTime",
    "Artist",
    "WhitePoint",
    "PrimaryChromaticities",
    "JpegIFOffset",
    "JpegIFByteCount",
    "YCbCrCoefficients",
    "YCbCrSubSampling",
    "YCbCrPositioning",
    "ReferenceBlackWhite",
    "RelatedImageFileFormat",
    "RelatedImageLength",
    "RelatedImageWidth",
    "CFARepeatPatternDim",
    "CFAPattern",
    "BatteryLevel",
    "Copyright",
    "ExposureTime",
    "FNumber",
    "ExifOffset",
    "InterColorProfile",
    "ExposureProgram",
    "SpectralSensitivity",
    "GPSInfo",
    "ISOSpeedRatings",
    "OECF",
    "Interlace",
    "TimeZoneOffset",
    "SelfTimerMode",
    "ExifVersion",
    "DateTimeOriginal",
    "DateTimeDigitized",
    "ComponentsConfiguration",
    "CompressedBitsPerPixel",
    "CompressedBitsPerPixel",
    "ShutterSpeedValue",
    "ApertureValue",
    "BrightnessValue",
    "ExposureBiasValue",
    "MaxApertureValue",
    "SubjectDistance",
    "MeteringMode",
    "LightSource",
    "Flash",
    "FocalLength",
    "FlashEnergy",
    "SpatialFrequencyResponse",
    "Noise",
    "ImageNumber",
    "SecurityClassification",
    "ImageHistory",
    "SubjectLocation",
    "ExposureIndex",
    "TIFF/EPStandardID",
    "UserComment",
    "SubsecTime",
    "SubsecTimeOriginal",
    "SubsecTimeDigitized",
    "FlashPixVersion",
    "ColorSpace",
    "ExifImageWidth",
    "ExifImageHeight",
    "RelatedSoundFile",
    "ExifInteroperabilityOffset",
    "FlashEnergy",
    "SpatialFrequencyResponse",
    "FocalPlaneXResolution",
    "FocalPlaneYResolution",
    "FocalPlaneResolutionUnit",
    "SubjectLocation",
    "ExposureIndex",
    "SensingMethod",
    "FileSource",
    "SceneType",
    "CFAPattern",
    ]

# update_exif {{{
def update_exif(app, album, filename):
    exifdir = os.path.join(app.config['CACHE_DIR'], album, 'exif')
    exiffile = os.path.join(exifdir, os.path.basename(filename) + '.exif')
    if not os.path.exists(exifdir):
        os.mkdir(exifdir)
    img = Image.open(os.path.join(app.config['ALBUMS_DIR'], album, filename))
    exif = img._getexif()

    if exif == None:
        return

    ret = {}
    if exif:
        for tag, value in exif.items():
            decoded = TAGS.get(tag, tag)
            ret[decoded] = value
    f = open(exiffile, 'w')
    for key in supported_exiftags:
        if ret.has_key(key):
            f.write("%s|%s\n" % (key, ret[key]))
    f.close()
# }}}

def get_exif(app, album, filename):
    exifdir = os.path.join(app.config['CACHE_DIR'], album, 'exif')
    exiffile = os.path.join(exifdir, os.path.basename(filename) + '.exif')

    exif = {}

    if os.path.exists(exiffile):
        f = open(exiffile)
        for line in f.readline():
            exif[line.split('|')[0]] = line.split('|')[1]
        f.close()

    return exif

<commit_msg>fix exif handling<commit_after>from ExifTags import TAGS
import os, Image

supported_exiftags = [
    "ImageWidth",
    "ImageLength",
    "BitsPerSample",
    "Compression",
    "PhotometricInterpretation",
    "ImageDescription",
    "Make",
    "Model",
    "StripOffsets",
    "Orientation",
    "SamplesPerPixel",
    "RowsPerStrip",
    "StripByteConunts",
    "XResolution",
    "YResolution",
    "PlanarConfiguration",
    "ResolutionUnit",
    "TransferFunction",
    "Software",
    "DateTime",
    "Artist",
    "WhitePoint",
    "PrimaryChromaticities",
    "JpegIFOffset",
    "JpegIFByteCount",
    "YCbCrCoefficients",
    "YCbCrSubSampling",
    "YCbCrPositioning",
    "ReferenceBlackWhite",
    "RelatedImageFileFormat",
    "RelatedImageLength",
    "RelatedImageWidth",
    "CFARepeatPatternDim",
    "CFAPattern",
    "BatteryLevel",
    "Copyright",
    "ExposureTime",
    "FNumber",
    "ExifOffset",
    "InterColorProfile",
    "ExposureProgram",
    "SpectralSensitivity",
    "GPSInfo",
    "ISOSpeedRatings",
    "OECF",
    "Interlace",
    "TimeZoneOffset",
    "SelfTimerMode",
    "ExifVersion",
    "DateTimeOriginal",
    "DateTimeDigitized",
    "ComponentsConfiguration",
    "CompressedBitsPerPixel",
    "CompressedBitsPerPixel",
    "ShutterSpeedValue",
    "ApertureValue",
    "BrightnessValue",
    "ExposureBiasValue",
    "MaxApertureValue",
    "SubjectDistance",
    "MeteringMode",
    "LightSource",
    "Flash",
    "FocalLength",
    "FlashEnergy",
    "SpatialFrequencyResponse",
    "Noise",
    "ImageNumber",
    "SecurityClassification",
    "ImageHistory",
    "SubjectLocation",
    "ExposureIndex",
    "TIFF/EPStandardID",
    "UserComment",
    "SubsecTime",
    "SubsecTimeOriginal",
    "SubsecTimeDigitized",
    "FlashPixVersion",
    "ColorSpace",
    "ExifImageWidth",
    "ExifImageHeight",
    "RelatedSoundFile",
    "ExifInteroperabilityOffset",
    "FlashEnergy",
    "SpatialFrequencyResponse",
    "FocalPlaneXResolution",
    "FocalPlaneYResolution",
    "FocalPlaneResolutionUnit",
    "SubjectLocation",
    "ExposureIndex",
    "SensingMethod",
    "FileSource",
    "SceneType",
    "CFAPattern",
    ]

# update_exif {{{
def update_exif(app, album, filename):
    exifdir = os.path.join(app.config['CACHE_DIR'], album, 'exif')
    exiffile = os.path.join(exifdir, os.path.basename(filename) + '.exif')
    if not os.path.exists(exifdir):
        os.mkdir(exifdir)
    img = Image.open(os.path.join(app.config['ALBUMS_DIR'], album, filename))
    exif = img._getexif()

    if exif == None:
        return

    ret = {}
    if exif:
        for tag, value in exif.items():
            decoded = TAGS.get(tag, tag)
            ret[decoded] = value
    f = open(exiffile, 'w')
    for key in supported_exiftags:
        if ret.has_key(key):
            f.write("%s|%s\n" % (key, ret[key]))
    f.close()
    return ret
# }}}

def get_exif(app, album, filename):
    exifdir = os.path.join(app.config['CACHE_DIR'], album, 'exif')
    exiffile = os.path.join(exifdir, os.path.basename(filename) + '.exif')

    exif = {}

    if os.path.exists(exiffile):
        f = open(exiffile)
        for line in f.readlines():
            line_arr = line.split('|')
            if len(line_arr) > 1:
                exif[line_arr[0]] = line_arr[1]
        f.close()
    else:
        exif = update_exif()

    return exif

<|endoftext|>


<commit_before>try:
    # Linux
    from libmesh import meshing
    from libgeom2d import geom2d
    from libcsg import csg
except:
    # Windows
    from nglib import *

<commit_msg>netgen module fix<commit_after>import sys
try:
    # Linux
    from libmesh import meshing
    from libgeom2d import geom2d
    from libcsg import csg
except:
    # Windows
    from nglib import *

sys.modules['netgen.meshing'] = meshing
sys.modules['netgen.geom2d'] = geom2d
sys.modules['netgen.csg'] = csg
del sys

<|endoftext|>


<commit_before>import re
from setuptools import setup

def find_version(filename):
    _version_re = re.compile(r"__version__ = '(.*)'")
    for line in open(filename):
        version_match = _version_re.match(line)
        if version_match:
            return version_match.group(1)

__version__ = find_version('nifstd_tools/__init__.py')

with open('README.md', 'rt') as f:
    long_description = f.read()

tests_require = ['pytest', 'pytest-runner']
setup(
    name='nifstd-tools',
    version=__version__,
    description='utilities for working with the NIF ontology',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='https://github.com/tgbugs/pyontutils/tree/master/nifstd',
    author='Tom Gillespie',
    author_email='tgbugs@gmail.com',
    license='MIT',
    classifiers=[
        'Development Status :: 4 - Beta',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],
    keywords='nif nifstd ontology pyontutils neuroscience',
    packages=['nifstd_tools'],
    python_requires='>=3.6',
    tests_require=tests_require,
    install_requires=[
        'beautifulsoup4',
        'flask',
        'nbconvert',
        'nbformat',
        'psutil',
        'pymysql',
        'pyontutils>=0.1.20',
        'sqlalchemy',
    ],
    extras_require={'dev': ['mysql-connector',
                            'protobuf',
                            'pytest-cov',
                            'wheel',
                           ],
                    'spell': ['hunspell'],
                    'test': tests_require,
    },
    scripts=['bin/ttlcmp'],
    entry_points={
        'console_scripts': [
            'ont-docs=nifstd_tools.docs:main',
            'ontree=nifstd_tools.ontree:main',
            'registry-sync=nifstd_tools.scr_sync:main',
            'slimgen=nifstd_tools.slimgen:main',
        ],
    },
    data_files=[('share/nifstd/resources/sparc_term_versions/',
                 ['resources/sparc_term_versions/sparc_terms2-mod.txt'])]
)
<commit_msg>nifstd setup.py networkx dep, bump pyontutils dep<commit_after>import re
from setuptools import setup

def find_version(filename):
    _version_re = re.compile(r"__version__ = '(.*)'")
    for line in open(filename):
        version_match = _version_re.match(line)
        if version_match:
            return version_match.group(1)

__version__ = find_version('nifstd_tools/__init__.py')

with open('README.md', 'rt') as f:
    long_description = f.read()

tests_require = ['pytest', 'pytest-runner']
setup(
    name='nifstd-tools',
    version=__version__,
    description='utilities for working with the NIF ontology',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='https://github.com/tgbugs/pyontutils/tree/master/nifstd',
    author='Tom Gillespie',
    author_email='tgbugs@gmail.com',
    license='MIT',
    classifiers=[
        'Development Status :: 4 - Beta',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],
    keywords='nif nifstd ontology pyontutils neuroscience',
    packages=['nifstd_tools'],
    python_requires='>=3.6',
    tests_require=tests_require,
    install_requires=[
        'beautifulsoup4',
        'flask',
        'nbconvert',
        'nbformat',
        'networkx',
        'psutil',
        'pymysql',
        'pyontutils>=0.1.21',
        'sqlalchemy',
    ],
    extras_require={'dev': ['mysql-connector',
                            'protobuf',
                            'pytest-cov',
                            'wheel',
                           ],
                    'spell': ['hunspell'],
                    'test': tests_require,
    },
    scripts=['bin/ttlcmp'],
    entry_points={
        'console_scripts': [
            'ont-docs=nifstd_tools.docs:main',
            'ontree=nifstd_tools.ontree:main',
            'registry-sync=nifstd_tools.scr_sync:main',
            'slimgen=nifstd_tools.slimgen:main',
        ],
    },
    data_files=[('share/nifstd/resources/sparc_term_versions/',
                 ['resources/sparc_term_versions/sparc_terms2-mod.txt'])]
)
<|endoftext|>


<commit_before>from bs4 import BeautifulSoup
from fake_useragent import UserAgent
import urllib2
import pandas as pd
import datetime

base_url = "http://www.chittorgarh.com/report/nse_nifty_index_50_stocks_live_list/7/"
user_agent = UserAgent()
headers = { 'User-Agent': str(user_agent.random) }
req = urllib2.Request(base_url, None, headers)
read_url = urllib2.urlopen(req)
response = read_url.read()
soup = BeautifulSoup(response, "lxml")
table = soup.find_all("table", attrs={'class': 'table'})
table_data = [j for i in table for j in i.find_all("tr")]
table_header = [str(j.text.strip()) for d in table_data[0:1]
                for j in d.find_all("th")]
table_value = table_data[1:]
column_header = ["Company_Name", "Open", "High", "Low", "LTP", "Change", "LTP1", "Percentage_Change", "Shares_Traded", "Trades", "Date_Updated"]
dataset = []
for d in table_value:
    cols = d.find_all("td")
    cols = [str(element.text.strip()) for element in cols]
    dataset.append(tuple(cols))
data_frame = pd.DataFrame(data=dataset, columns=column_header)
data_frame['Date_Updated'] = pd.to_datetime(data_frame['Date_Updated'], format="%m/%d/%Y")
now = datetime.datetime.now()
csv_frame = data_frame.to_csv("today_{0}.csv".format(now), index=False)
<commit_msg>Modified: Removed column header.<commit_after>from bs4 import BeautifulSoup
from fake_useragent import UserAgent
import urllib2
import pandas as pd
import datetime

base_url = "http://www.chittorgarh.com/report/nse_nifty_index_50_stocks_live_list/7/"
user_agent = UserAgent()
headers = { 'User-Agent': str(user_agent.random) }
req = urllib2.Request(base_url, None, headers)
read_url = urllib2.urlopen(req)
response = read_url.read()
soup = BeautifulSoup(response, "lxml")
table = soup.find_all("table", attrs={'class': 'table'})
table_data = [j for i in table for j in i.find_all("tr")]
table_value = table_data[1:]
column_header = ["Company_Name", "Open", "High", "Low", "LTP", "Change", "LTP1", "Percentage_Change", "Shares_Traded", "Trades", "Date_Updated"]
dataset = []
for d in table_value:
    cols = d.find_all("td")
    cols = [str(element.text.strip()) for element in cols]
    dataset.append(tuple(cols))
data_frame = pd.DataFrame(data=dataset, columns=column_header)
data_frame['Date_Updated'] = pd.to_datetime(data_frame['Date_Updated'], format="%m/%d/%Y")
now = datetime.datetime.now()
csv_frame = data_frame.to_csv("today_{0}.csv".format(now), index=False)
<|endoftext|>


<commit_before>import re

MIDI_NOTE_VALUES = {
    "c": 0,
    "d": 2,
    "e": 4,
    "f": 5,
    "g": 7,
    "a": 9,
    "b": 11,
}

token_pattern = re.compile(r"""^\s*                 # INITIAL WHITESPACE
    (
        (                                           # NOTE
            (
                (?P<note>[abcdefg])                     # NOTE NAME
                (?P<octave>'+|,+) ?                     # OCTAVE ?
                ((?P<sharp>(is)+)|(?P<flat>(es)+)) ?    # ACCIDENTALS ?
                (=(?P<octave_check>'+|,+)) ?            # OCTAVE CHECK ?
                |                                       # or
                (?P<rest>r)                             # REST
            )
            (?P<duration>\d+\.*) ?                      # DURATION ?
            (\s*(?P<tie>~)) ?                           # TIE ?
        )
        |                                           # or
        \\(?P<command>(                             # COMMANDS
            relative | acciaccatura
        ))
        |                                           # or
        (?P<open_brace>{) | (?P<close_brace>})      # { or }
    )
    """,
    re.VERBOSE
)

def tokenize(s):
    while True:
        if s:
            m = token_pattern.match(s)
            if m:
                yield m.groupdict()
            else:
                raise Exception("unknown token at: '%s'" % s[:20])
            s = s[m.end():]
        else:
            raise StopIteration

def note_tuple(token_dict, relative_note_tuple=None):
    note = token_dict["note"]
    octave_marker = token_dict["octave"]
    accidental_sharp = token_dict["sharp"]
    accidental_flat = token_dict["flat"]
    accidental_change = 0

    if relative_note_tuple:
        prev_note, prev_accidental_change, prev_octave = relative_note_tuple

        diff = MIDI_NOTE_VALUES[note] - prev_note
        if diff >= 7:
            base_octave = prev_octave - 1
        elif diff <= -7:
            base_octave = prev_octave + 1
        else:
            base_octave = prev_octave
    else:
        base_octave = 4

    if octave_marker is None:
        octave = base_octave
    elif "'" in octave_marker:
        octave = base_octave + len(octave_marker)
    elif "," in octave_marker:
        octave = base_octave - len(octave_marker)
    if accidental_sharp:
        accidental_change += len(accidental_sharp) / 2
    if accidental_flat:
        accidental_change -= len(accidental_flat) / 2

    return MIDI_NOTE_VALUES[note], accidental_change, octave

def parse_duration(duration_marker):
    if "." in duration_marker:
        first_dot = duration_marker.find(".")
        core = int(duration_marker[:first_dot])
        # this doesn't actually check they are all dots, but regex wouldn't
        # match in the first place otherwise
        dots = len(duration_marker[first_dot:])
    else:
        core = int(duration_marker)
        dots = 0

    duration = (2 - (2**-dots)) * 64 / core

    return duration

def process_note(token_dict, relative_mode, prev_note_tuple):
    # @@@ there is still code duplication between here and the main parsing further on
    # @@@ some of the args passed in above could be avoided if this and parse_block were methods on a class

    duration_marker = token_dict["duration"]
    # duration must be explicit
    duration = parse_duration(duration_marker)

    if relative_mode:
        note_base, accidental_change, octave = note_tuple(token_dict, relative_note_tuple=prev_note_tuple)
    else:
        note_base, accidental_change, octave = note_tuple(token_dict)

    note_value = note_base + (12 * octave) + accidental_change

    return note_value, duration

def parse_block(token_generator, prev_note_tuple = None, relative_mode = False, offset = 0):
    prev_duration = 16
    tie_deferred = False

    while True:
        token_dict = token_generator.next()

        command = token_dict["command"]
        open_brace = token_dict["open_brace"]
        close_brace = token_dict["close_brace"]

        if command:
            if command == "relative":

                token_dict = token_generator.next()

                base_note_tuple = note_tuple(token_dict)

                token_dict = token_generator.next()
                if not token_dict["open_brace"]:
                    raise Exception("\\relative must be followed by note then {...} block")

                for obj in parse_block(token_generator, prev_note_tuple=base_note_tuple, relative_mode=True, offset=offset):
                    yield obj
            elif command == "acciaccatura":
                # @@@ there is much code duplication between here and the main parsing further on

                token_dict = token_generator.next()
                note_value, duration = process_note(token_dict, relative_mode, prev_note_tuple)
                yield (offset - duration / 2, note_value, duration / 2)

                token_dict = token_generator.next()
                note_value, duration = process_note(token_dict, relative_mode, prev_note_tuple)
                yield (offset, note_value, duration)

                offset += duration
                prev_duration = duration

                # @@@ this should be uncommented but I'll wait until a unit test proves it should be uncommented!
                # prev_note_tuple = note_base, accidental_change, octave

        elif open_brace:
            for obj in parse_block(token_generator):
                yield obj
        elif close_brace:
            raise StopIteration
        else:
            duration_marker = token_dict["duration"]
            rest = token_dict["rest"]
            tie = token_dict["tie"]

            if duration_marker is None:
                duration = prev_duration
            else:
                duration = parse_duration(duration_marker)

            if not rest:
                if relative_mode:
                    note_base, accidental_change, octave = note_tuple(token_dict, relative_note_tuple=prev_note_tuple)
                else:
                    note_base, accidental_change, octave = note_tuple(token_dict)
                note_value = note_base + (12 * octave) + accidental_change

                if tie_deferred:
                    # if the previous note was deferred due to a tie
                    prev_note_value = prev_note_tuple[0] + (12 * prev_note_tuple[2]) + prev_note_tuple[1]
                    if note_value != prev_note_value:
                        raise Exception("ties are only supported between notes of same pitch")
                    duration += prev_duration
                    tie_deferred = False

                if tie:
                    # if there is a tie following this note, we defer it
                    tie_deferred = True
                else:
                    yield (offset, note_value, duration)

                prev_note_tuple = note_base, accidental_change, octave

            if not tie_deferred:
                offset += duration

            prev_duration = duration

def parse(s):
    return parse_block(tokenize(s))
<commit_msg>make sure duration is an integer<commit_after>import re

MIDI_NOTE_VALUES = {
    "c": 0,
    "d": 2,
    "e": 4,
    "f": 5,
    "g": 7,
    "a": 9,
    "b": 11,
}

token_pattern = re.compile(r"""^\s*                 # INITIAL WHITESPACE
    (
        (                                           # NOTE
            (
                (?P<note>[abcdefg])                     # NOTE NAME
                (?P<octave>'+|,+) ?                     # OCTAVE ?
                ((?P<sharp>(is)+)|(?P<flat>(es)+)) ?    # ACCIDENTALS ?
                (=(?P<octave_check>'+|,+)) ?            # OCTAVE CHECK ?
                |                                       # or
                (?P<rest>r)                             # REST
            )
            (?P<duration>\d+\.*) ?                      # DURATION ?
            (\s*(?P<tie>~)) ?                           # TIE ?
        )
        |                                           # or
        \\(?P<command>(                             # COMMANDS
            relative | acciaccatura
        ))
        |                                           # or
        (?P<open_brace>{) | (?P<close_brace>})      # { or }
    )
    """,
    re.VERBOSE
)

def tokenize(s):
    while True:
        if s:
            m = token_pattern.match(s)
            if m:
                yield m.groupdict()
            else:
                raise Exception("unknown token at: '%s'" % s[:20])
            s = s[m.end():]
        else:
            raise StopIteration

def note_tuple(token_dict, relative_note_tuple=None):
    note = token_dict["note"]
    octave_marker = token_dict["octave"]
    accidental_sharp = token_dict["sharp"]
    accidental_flat = token_dict["flat"]
    accidental_change = 0

    if relative_note_tuple:
        prev_note, prev_accidental_change, prev_octave = relative_note_tuple

        diff = MIDI_NOTE_VALUES[note] - prev_note
        if diff >= 7:
            base_octave = prev_octave - 1
        elif diff <= -7:
            base_octave = prev_octave + 1
        else:
            base_octave = prev_octave
    else:
        base_octave = 4

    if octave_marker is None:
        octave = base_octave
    elif "'" in octave_marker:
        octave = base_octave + len(octave_marker)
    elif "," in octave_marker:
        octave = base_octave - len(octave_marker)
    if accidental_sharp:
        accidental_change += len(accidental_sharp) / 2
    if accidental_flat:
        accidental_change -= len(accidental_flat) / 2

    return MIDI_NOTE_VALUES[note], accidental_change, octave

def parse_duration(duration_marker):
    if "." in duration_marker:
        first_dot = duration_marker.find(".")
        core = int(duration_marker[:first_dot])
        # this doesn't actually check they are all dots, but regex wouldn't
        # match in the first place otherwise
        dots = len(duration_marker[first_dot:])
    else:
        core = int(duration_marker)
        dots = 0

    duration = int((2 - (2**-dots)) * 64 / core)

    return duration

def process_note(token_dict, relative_mode, prev_note_tuple):
    # @@@ there is still code duplication between here and the main parsing further on
    # @@@ some of the args passed in above could be avoided if this and parse_block were methods on a class

    duration_marker = token_dict["duration"]
    # duration must be explicit
    duration = parse_duration(duration_marker)

    if relative_mode:
        note_base, accidental_change, octave = note_tuple(token_dict, relative_note_tuple=prev_note_tuple)
    else:
        note_base, accidental_change, octave = note_tuple(token_dict)

    note_value = note_base + (12 * octave) + accidental_change

    return note_value, duration

def parse_block(token_generator, prev_note_tuple = None, relative_mode = False, offset = 0):
    prev_duration = 16
    tie_deferred = False

    while True:
        token_dict = token_generator.next()

        command = token_dict["command"]
        open_brace = token_dict["open_brace"]
        close_brace = token_dict["close_brace"]

        if command:
            if command == "relative":

                token_dict = token_generator.next()

                base_note_tuple = note_tuple(token_dict)

                token_dict = token_generator.next()
                if not token_dict["open_brace"]:
                    raise Exception("\\relative must be followed by note then {...} block")

                for obj in parse_block(token_generator, prev_note_tuple=base_note_tuple, relative_mode=True, offset=offset):
                    yield obj
            elif command == "acciaccatura":
                # @@@ there is much code duplication between here and the main parsing further on

                token_dict = token_generator.next()
                note_value, duration = process_note(token_dict, relative_mode, prev_note_tuple)
                yield (offset - duration / 2, note_value, duration / 2)

                token_dict = token_generator.next()
                note_value, duration = process_note(token_dict, relative_mode, prev_note_tuple)
                yield (offset, note_value, duration)

                offset += duration
                prev_duration = duration

                # @@@ this should be uncommented but I'll wait until a unit test proves it should be uncommented!
                # prev_note_tuple = note_base, accidental_change, octave

        elif open_brace:
            for obj in parse_block(token_generator):
                yield obj
        elif close_brace:
            raise StopIteration
        else:
            duration_marker = token_dict["duration"]
            rest = token_dict["rest"]
            tie = token_dict["tie"]

            if duration_marker is None:
                duration = prev_duration
            else:
                duration = parse_duration(duration_marker)

            if not rest:
                if relative_mode:
                    note_base, accidental_change, octave = note_tuple(token_dict, relative_note_tuple=prev_note_tuple)
                else:
                    note_base, accidental_change, octave = note_tuple(token_dict)
                note_value = note_base + (12 * octave) + accidental_change

                if tie_deferred:
                    # if the previous note was deferred due to a tie
                    prev_note_value = prev_note_tuple[0] + (12 * prev_note_tuple[2]) + prev_note_tuple[1]
                    if note_value != prev_note_value:
                        raise Exception("ties are only supported between notes of same pitch")
                    duration += prev_duration
                    tie_deferred = False

                if tie:
                    # if there is a tie following this note, we defer it
                    tie_deferred = True
                else:
                    yield (offset, note_value, duration)

                prev_note_tuple = note_base, accidental_change, octave

            if not tie_deferred:
                offset += duration

            prev_duration = duration

def parse(s):
    return parse_block(tokenize(s))
<|endoftext|>


<commit_before>from __future__ import print_function, division
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
from math import sqrt

SPINE_COLOR = 'gray'

_to_ordinalf_np_vectorized = np.vectorize(mdates._to_ordinalf)

def plot_series(series, ax=None, fig=None,
                date_format='%d/%m/%y %H:%M:%S', tz_localize=True, **kwargs):
    """Plot function for series which is about 5 times faster than
    pd.Series.plot().

    Parameters
    ----------
    series : pd.Series
    ax : matplotlib Axes, optional
        If not provided then will generate our own axes.
    fig : matplotlib Figure
    date_format : str, optional, default='%d/%m/%y %H:%M:%S'
    tz_localize : boolean, optional, default is True
        if False then display UTC times.

    Can also use all **kwargs expected by `ax.plot`
    """
    if series is None or len(series) == 0:
        return ax

    if ax is None:
        ax = plt.gca()

    if fig is None:
        fig = plt.gcf()

    x = _to_ordinalf_np_vectorized(series.index.to_pydatetime())
    ax.plot(x, series, **kwargs)
    tz = series.index.tzinfo if tz_localize else None
    ax.xaxis.set_major_formatter(
        mdates.DateFormatter(date_format, tz=tz))
    ax.set_ylabel('watts')
    fig.autofmt_xdate()
    return ax

def plot_pairwise_heatmap(df, labels, edgecolors='w',
                          cmap=matplotlib.cm.RdYlBu_r, log=False):
    """
    Plots a heatmap of a 'square' df
    Rows and columns are same and the values in this dataframe
    correspond to the computation b/w row,column.
    This plot can be used for plotting pairwise_correlation
    or pairwise_mutual_information or any method which works
    similarly
    """
    width = len(df.columns) / 4
    height = len(df.index) / 4

    fig, ax = plt.subplots(figsize=(width, height))

    heatmap = ax.pcolor(
        df,
        edgecolors=edgecolors,  # put white lines between squares in heatmap
        cmap=cmap,
        norm=matplotlib.colors.LogNorm() if log else None)

    ax.autoscale(tight=True)  # get rid of whitespace in margins of heatmap
    ax.set_aspect('equal')  # ensure heatmap cells are square
    ax.xaxis.set_ticks_position('top')  # put column labels at the top
    # turn off ticks:
    ax.tick_params(bottom='off', top='off', left='off', right='off')

    plt.yticks(np.arange(len(df.index)) + 0.5, labels)
    plt.xticks(np.arange(len(df.columns)) + 0.5, labels, rotation=90)

    # ugliness from http://matplotlib.org/users/tight_layout_guide.html
    from mpl_toolkits.axes_grid1 import make_axes_locatable
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", "3%", pad="1%")
    plt.colorbar(heatmap, cax=cax)

def latexify(fig_width=None, fig_height=None, columns=1):
    """Set up matplotlib's RC params for LaTeX plotting.
    Call this before plotting a figure.

    Parameters
    ----------
    fig_width : float, optional, inches
    fig_height : float,  optional, inches
    columns : {1, 2}
    """

    # code adapted from http://www.scipy.org/Cookbook/Matplotlib/LaTeX_Examples

    # Width and max height in inches for IEEE journals taken from
    # computer.org/cms/Computer.org/Journal%20templates/transactions_art_guide.pdf

    assert columns in [1, 2]

    if fig_width is None:
        fig_width = 3.39 if columns == 1 else 6.9  # width in inches

    if fig_height is None:
        golden_mean = (sqrt(5)-1.0)/2.0    # Aesthetic ratio
        fig_height = fig_width * golden_mean  # height in inches

    MAX_HEIGHT_INCHES = 8.0
    if fig_height > MAX_HEIGHT_INCHES:
        print("WARNING: fig_height too large:" + fig_height +
              "so will reduce to" + MAX_HEIGHT_INCHES + "inches.")
        fig_height = MAX_HEIGHT_INCHES

    params = {
        'backend': 'ps',
        'text.latex.preamble': ['\usepackage{gensymb}'],
        'axes.labelsize': 8,  # fontsize for x and y labels (was 10)
        'axes.titlesize': 8,
        'font.size': 8,  # was 10
        'legend.fontsize': 8,  # was 10
        'xtick.labelsize': 8,
        'ytick.labelsize': 8,
        'text.usetex': True,
        'figure.figsize': [fig_width, fig_height],
        'font.family': 'serif'
    }
    matplotlib.rcParams.update(params)

def format_axes(ax):

    for spine in ['top', 'right']:
        ax.spines[spine].set_visible(False)

    for spine in ['left', 'bottom']:
        ax.spines[spine].set_color(SPINE_COLOR)
        ax.spines[spine].set_linewidth(0.5)

    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('left')

    for axis in [ax.xaxis, ax.yaxis]:
        axis.set_tick_params(direction='out', color=SPINE_COLOR)

#    matplotlib.pyplot.tight_layout()

    return ax
<commit_msg>pass fontsize as argument<commit_after>from __future__ import print_function, division
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
from math import sqrt

_to_ordinalf_np_vectorized = np.vectorize(mdates._to_ordinalf)

def plot_series(series, ax=None, fig=None,
                date_format='%d/%m/%y %H:%M:%S', tz_localize=True, **kwargs):
    """Plot function for series which is about 5 times faster than
    pd.Series.plot().

    Parameters
    ----------
    series : pd.Series
    ax : matplotlib Axes, optional
        If not provided then will generate our own axes.
    fig : matplotlib Figure
    date_format : str, optional, default='%d/%m/%y %H:%M:%S'
    tz_localize : boolean, optional, default is True
        if False then display UTC times.

    Can also use all **kwargs expected by `ax.plot`
    """
    if series is None or len(series) == 0:
        return ax

    if ax is None:
        ax = plt.gca()

    if fig is None:
        fig = plt.gcf()

    x = _to_ordinalf_np_vectorized(series.index.to_pydatetime())
    ax.plot(x, series, **kwargs)
    tz = series.index.tzinfo if tz_localize else None
    ax.xaxis.set_major_formatter(
        mdates.DateFormatter(date_format, tz=tz))
    ax.set_ylabel('watts')
    fig.autofmt_xdate()
    return ax

def plot_pairwise_heatmap(df, labels, edgecolors='w',
                          cmap=matplotlib.cm.RdYlBu_r, log=False):
    """
    Plots a heatmap of a 'square' df
    Rows and columns are same and the values in this dataframe
    correspond to the computation b/w row,column.
    This plot can be used for plotting pairwise_correlation
    or pairwise_mutual_information or any method which works
    similarly
    """
    width = len(df.columns) / 4
    height = len(df.index) / 4

    fig, ax = plt.subplots(figsize=(width, height))

    heatmap = ax.pcolor(
        df,
        edgecolors=edgecolors,  # put white lines between squares in heatmap
        cmap=cmap,
        norm=matplotlib.colors.LogNorm() if log else None)

    ax.autoscale(tight=True)  # get rid of whitespace in margins of heatmap
    ax.set_aspect('equal')  # ensure heatmap cells are square
    ax.xaxis.set_ticks_position('top')  # put column labels at the top
    # turn off ticks:
    ax.tick_params(bottom='off', top='off', left='off', right='off')

    plt.yticks(np.arange(len(df.index)) + 0.5, labels)
    plt.xticks(np.arange(len(df.columns)) + 0.5, labels, rotation=90)

    # ugliness from http://matplotlib.org/users/tight_layout_guide.html
    from mpl_toolkits.axes_grid1 import make_axes_locatable
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", "3%", pad="1%")
    plt.colorbar(heatmap, cax=cax)

def latexify(fig_width=None, fig_height=None, columns=1, fontsize=8):
    """Set up matplotlib's RC params for LaTeX plotting.
    Call this before plotting a figure.

    Parameters
    ----------
    fig_width : float, optional, inches
    fig_height : float,  optional, inches
    columns : {1, 2}
    """

    # code adapted from http://www.scipy.org/Cookbook/Matplotlib/LaTeX_Examples

    # Width and max height in inches for IEEE journals taken from
    # computer.org/cms/Computer.org/Journal%20templates/transactions_art_guide.pdf

    assert columns in [1, 2]

    if fig_width is None:
        fig_width = 3.39 if columns == 1 else 6.9  # width in inches

    if fig_height is None:
        golden_mean = (sqrt(5)-1.0)/2.0    # Aesthetic ratio
        fig_height = fig_width * golden_mean  # height in inches

    MAX_HEIGHT_INCHES = 8.0
    if fig_height > MAX_HEIGHT_INCHES:
        print("WARNING: fig_height too large:" + fig_height +
              "so will reduce to" + MAX_HEIGHT_INCHES + "inches.")
        fig_height = MAX_HEIGHT_INCHES

    params = {
        'backend': 'ps',
        'text.latex.preamble': ['\usepackage{gensymb}'],
        'axes.labelsize': fontsize,  # fontsize for x and y labels (was 10)
        'axes.titlesize': fontsize,
        'font.size': fontsize,
        'legend.fontsize': fontsize,
        'xtick.labelsize': fontsize,
        'ytick.labelsize': fontsize,
        'text.usetex': True,
        'figure.figsize': [fig_width, fig_height],
        'font.family': 'serif'
    }
    matplotlib.rcParams.update(params)

def format_axes(ax, spine_color='gray'):

    for spine in ['top', 'right']:
        ax.spines[spine].set_visible(False)

    for spine in ['left', 'bottom']:
        ax.spines[spine].set_color(spine_color)
        ax.spines[spine].set_linewidth(0.5)

    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('left')

    for axis in [ax.xaxis, ax.yaxis]:
        axis.set_tick_params(direction='out', color=spine_color)

#    matplotlib.pyplot.tight_layout()

    return ax
<|endoftext|>


<commit_before>from __future__ import print_function, division
import numpy as np
import pandas as pd
import networkx as nx
from os.path import isdir, dirname, abspath
from os import getcwd
from inspect import currentframe, getfile, getsourcefile
from sys import getfilesystemencoding, stdout
from IPython.core.display import HTML, display
from collections import OrderedDict
import datetime
import pytz
from nilmtk.datastore import HDFDataStore, CSVDataStore
import warnings

# Python 2/3 compatibility
from six import iteritems
from past.builtins import basestring

def show_versions():
    """Prints versions of various dependencies"""
    output = OrderedDict()
    output["Date"] = str(datetime.datetime.now())
    import sys
    import platform
    output["Platform"] = str(platform.platform())
    system_information = sys.version_info
    output["System version"] = "{}.{}".format(system_information.major,
                                              system_information.minor)

    PACKAGES = [
        "nilmtk", "nilm_metadata", "numpy", "matplotlib", "pandas", "sklearn",
        "hmmlearn"]
    for package_name in PACKAGES:
        key = package_name + " version"
        try:
            exec("import " + package_name)
        except ImportError:
            output[key] = "Not found"
        else:
            output[key] = eval(package_name + ".__version__")

    try:
        print(pd.show_versions())
    except:
        pass
    else:
        print("")

    for k, v in iteritems(output):
        print("{}: {}".format(k, v))

def timedelta64_to_secs(timedelta):
    """Convert `timedelta` to seconds.

    Parameters
    ----------
    timedelta : np.timedelta64

    Returns
    -------
    float : seconds
    """
    if len(timedelta) == 0:
        return np.array([])
    else:
        return timedelta / np.timedelta64(1, 's')

def tree_root(graph):
    """Returns the object that is the root of the tree.

    Parameters
    ----------
    graph : networkx.Graph
    """
    # from http://stackoverflow.com/a/4123177/732596
    assert isinstance(graph, nx.Graph)
    roots = [node for node, in_degree in graph.in_degree()
             if in_degree == 0]
    n_roots = len(roots)
    if n_roots > 1:
        raise RuntimeError('Tree has more than one root!')
    if n_roots == 0:
        raise RuntimeError('Tree has no root!')
    return roots[0]

def nodes_adjacent_to_root(graph):
    root = tree_root(graph)
    return graph.successors(root)

def index_of_column_name(df, name):
    for i, col_name in enumerate(df.columns):
        if col_name == name:
            return i
    raise KeyError(name)

def find_nearest(known_array, test_array):
    """Find closest value in `known_array` for each element in `test_array`.

    Parameters
    ----------
    known_array : numpy array
        consisting of scalar values only; shape: (m, 1)
    test_array : numpy array
        consisting of scalar values only; shape: (n, 1)

    Returns
    -------
    indices : numpy array; shape: (n, 1)
        For each value in `test_array` finds the index of the closest value
        in `known_array`.
    residuals : numpy array; shape: (n, 1)
        For each value in `test_array` finds the difference from the closest
        value in `known_array`.
    """
    # from http://stackoverflow.com/a/20785149/732596

    index_sorted = np.argsort(known_array)
    known_array_sorted = known_array[index_sorted]

    idx1 = np.searchsorted(known_array_sorted, test_array)
    idx2 = np.clip(idx1 - 1, 0, len(known_array_sorted)-1)
    idx3 = np.clip(idx1,     0, len(known_array_sorted)-1)

    diff1 = known_array_sorted[idx3] - test_array
    diff2 = test_array - known_array_sorted[idx2]

    indices = index_sorted[np.where(diff1 <= diff2, idx3, idx2)]
    residuals = test_array - known_array[indices]
    return indices, residuals

def container_to_string(container, sep='_'):
    if isinstance(container, basestring):
        string = container
    else:
        try:
            string = sep.join([str(element) for element in container])
        except TypeError:
            string = str(container)
    return string

def simplest_type_for(values):
    n_values = len(values)
    if n_values == 1:
        return list(values)[0]
    elif n_values == 0:
        return
    else:
        return tuple(values)

def flatten_2d_list(list2d):
    list1d = []
    for item in list2d:
        if isinstance(item, basestring):
            list1d.append(item)
        else:
            try:
                len(item)
            except TypeError:
                list1d.append(item)
            else:
                list1d.extend(item)
    return list1d

def get_index(data):
    """
    Parameters
    ----------
    data : pandas.DataFrame or Series or DatetimeIndex

    Returns
    -------
    index : the index for the DataFrame or Series
    """
    if isinstance(data, (pd.DataFrame, pd.Series)):
        index = data.index
    elif isinstance(data, pd.DatetimeIndex):
        index = data
    else:
        raise TypeError('wrong type for `data`.')
    return index

def convert_to_timestamp(t):
    """
    Parameters
    ----------
    t : str or pd.Timestamp or datetime or None

    Returns
    -------
    pd.Timestamp or None
    """
    return None if t is None else pd.Timestamp(t)

def get_module_directory():
    # Taken from http://stackoverflow.com/a/6098238/732596
    path_to_this_file = dirname(getfile(currentframe()))
    if not isdir(path_to_this_file):
        encoding = getfilesystemencoding()
        path_to_this_file = dirname(unicode(__file__, encoding))
    if not isdir(path_to_this_file):
        abspath(getsourcefile(lambda _: None))
    if not isdir(path_to_this_file):
        path_to_this_file = getcwd()
    assert isdir(path_to_this_file), path_to_this_file + ' is not a directory'
    return path_to_this_file

def dict_to_html(dictionary):
    def format_string(value):
        try:
            if isinstance(value, basestring) and 'http' in value:
                html = '{url}'.format(url=value)
            else:
                html = '{}'.format(value)
        except UnicodeEncodeError:
            html = ''
        return html

    html = '
'
    for key, value in iteritems(dictionary):
        html += '
{}: '.format(key)
        if isinstance(value, list):
            html += '
'
            for item in value:
                html += '
{}
'.format(format_string(item))
            html += '
'
        elif isinstance(value, dict):
            html += dict_to_html(value)
        else:
            html += format_string(value)
        html += '
'
    html += '
'
    return html

def print_dict(dictionary):
    html = dict_to_html(dictionary)
    display(HTML(html))

def offset_alias_to_seconds(alias):
    """Seconds for each period length."""
    dr = pd.date_range('00:00', periods=2, freq=alias)
    return (dr[-1] - dr[0]).total_seconds()

def check_directory_exists(d):
    if not isdir(d):
        raise IOError("Directory '{}' does not exist.".format(d))

def tz_localize_naive(timestamp, tz):
    if tz is None:
        return timestamp
    if timestamp is None or pd.isnull(timestamp):
        return pd.NaT

    timestamp = pd.Timestamp(timestamp)
    if timestamp_is_naive(timestamp):
        timestamp = timestamp.tz_localize('UTC')

    return timestamp.tz_convert(tz)

def get_tz(df):
    index = df.index
    try:
        tz = index.tz
    except AttributeError:
        tz = None
    return tz

def timestamp_is_naive(timestamp):
    """
    Parameters
    ----------
    timestamp : pd.Timestamp or datetime.datetime

    Returns
    -------
    True if `timestamp` is naive (i.e. if it does not have a
    timezone associated with it).  See:
    https://docs.python.org/2/library/datetime.html#available-types
    """
    if timestamp.tzinfo is None:
        return True
    elif timestamp.tzinfo.utcoffset(timestamp) is None:
        return True
    else:
        return False

def get_datastore(filename, format, mode='a'):
    """
    Parameters
    ----------
    filename : string
    format : 'CSV' or 'HDF'
    mode : 'a' (append) or 'w' (write), optional

    Returns
    -------
    metadata : dict
    """
    if filename is not None:
        if format == 'HDF':
            return HDFDataStore(filename, mode)
        elif format == 'CSV':
            return CSVDataStore(filename)
        else:
            raise ValueError('format not recognised')
    else:
        ValueError('filename is None')

def normalise_timestamp(timestamp, freq):
    """Returns the nearest Timestamp to `timestamp` which would be
    in the set of timestamps returned by pd.DataFrame.resample(freq=freq)
    """
    timestamp = pd.Timestamp(timestamp)
    series = pd.Series(np.NaN, index=[timestamp])
    resampled = series.resample(freq).mean()
    return resampled.index[0]

def print_on_line(*strings):
    print(*strings, end="")
    stdout.flush()

def append_or_extend_list(lst, value):
    if value is None:
        return
    elif isinstance(value, list):
        lst.extend(value)
    else:
        lst.append(value)

def convert_to_list(list_like):
    return [] if list_like is None else list(list_like)

def most_common(lst):
    """Returns the most common entry in lst."""
    lst = list(lst)
    counts = {item: lst.count(item) for item in set(lst)}
    counts = pd.Series(counts)
    counts.sort()
    most_common = counts.index[-1]
    return most_common

def capitalise_first_letter(string):
    return string[0].upper() + string[1:]

def capitalise_index(index):
    labels = list(index)
    for i, label in enumerate(labels):
        labels[i] = capitalise_first_letter(label)
    return labels

def capitalise_legend(ax):
    legend_handles = ax.get_legend_handles_labels()
    labels = capitalise_index(legend_handles[1])
    ax.legend(legend_handles[0], labels)
    return ax

def safe_resample(data, **resample_kwargs):
    if data.empty:
        return data

    def _resample_chain(data, all_resample_kwargs):
        """_resample_chain provides a compatibility function for
        deprecated/removed DataFrame.resample kwargs"""

        rule = all_resample_kwargs.pop('rule')
        axis = all_resample_kwargs.pop('axis', None)
        on = all_resample_kwargs.pop('on', None)
        level = all_resample_kwargs.pop('level', None)

        resample_kwargs = {}
        if axis is not None: resample_kwargs['axis'] = axis
        if on is not None: resample_kwargs['on'] = on
        if level is not None: resample_kwargs['level'] = level

        fill_method_str = all_resample_kwargs.pop('fill_method', None)
        if fill_method_str:
            fill_method = lambda df: getattr(df, fill_method_str)()
        else:
            fill_method = lambda df: df

        how_str = all_resample_kwargs.pop('how', None)
        if how_str:
            how = lambda df: getattr(df, how_str)()
        else:
            how = lambda df: df

        if resample_kwargs:
            warnings.warn("Not all resample_kwargs were consumed: {}".format(repr(resample_kwargs)))

        return how(fill_method(data.resample(rule, **resample_kwargs)))

    try:
        data = _resample_chain(data, resample_kwargs)
    except pytz.AmbiguousTimeError:
        # Work-around for
        # https://github.com/pydata/pandas/issues/10117
        tz = data.index.tz.zone
        data = data.tz_convert('UTC')
        data = _resample_chain(data, resample_kwargs)

        data = data.tz_convert(tz)
    return data
<commit_msg>Remedy for duplicate indexes in dataset<commit_after>from __future__ import print_function, division
import numpy as np
import pandas as pd
import networkx as nx
from os.path import isdir, dirname, abspath
from os import getcwd
from inspect import currentframe, getfile, getsourcefile
from sys import getfilesystemencoding, stdout
from IPython.core.display import HTML, display
from collections import OrderedDict
import datetime
import pytz
from nilmtk.datastore import HDFDataStore, CSVDataStore
import warnings

# Python 2/3 compatibility
from six import iteritems
from past.builtins import basestring

def show_versions():
    """Prints versions of various dependencies"""
    output = OrderedDict()
    output["Date"] = str(datetime.datetime.now())
    import sys
    import platform
    output["Platform"] = str(platform.platform())
    system_information = sys.version_info
    output["System version"] = "{}.{}".format(system_information.major,
                                              system_information.minor)

    PACKAGES = [
        "nilmtk", "nilm_metadata", "numpy", "matplotlib", "pandas", "sklearn",
        "hmmlearn"]
    for package_name in PACKAGES:
        key = package_name + " version"
        try:
            exec("import " + package_name)
        except ImportError:
            output[key] = "Not found"
        else:
            output[key] = eval(package_name + ".__version__")

    try:
        print(pd.show_versions())
    except:
        pass
    else:
        print("")

    for k, v in iteritems(output):
        print("{}: {}".format(k, v))

def timedelta64_to_secs(timedelta):
    """Convert `timedelta` to seconds.

    Parameters
    ----------
    timedelta : np.timedelta64

    Returns
    -------
    float : seconds
    """
    if len(timedelta) == 0:
        return np.array([])
    else:
        return timedelta / np.timedelta64(1, 's')

def tree_root(graph):
    """Returns the object that is the root of the tree.

    Parameters
    ----------
    graph : networkx.Graph
    """
    # from http://stackoverflow.com/a/4123177/732596
    assert isinstance(graph, nx.Graph)
    roots = [node for node, in_degree in graph.in_degree()
             if in_degree == 0]
    n_roots = len(roots)
    if n_roots > 1:
        raise RuntimeError('Tree has more than one root!')
    if n_roots == 0:
        raise RuntimeError('Tree has no root!')
    return roots[0]

def nodes_adjacent_to_root(graph):
    root = tree_root(graph)
    return graph.successors(root)

def index_of_column_name(df, name):
    for i, col_name in enumerate(df.columns):
        if col_name == name:
            return i
    raise KeyError(name)

def find_nearest(known_array, test_array):
    """Find closest value in `known_array` for each element in `test_array`.

    Parameters
    ----------
    known_array : numpy array
        consisting of scalar values only; shape: (m, 1)
    test_array : numpy array
        consisting of scalar values only; shape: (n, 1)

    Returns
    -------
    indices : numpy array; shape: (n, 1)
        For each value in `test_array` finds the index of the closest value
        in `known_array`.
    residuals : numpy array; shape: (n, 1)
        For each value in `test_array` finds the difference from the closest
        value in `known_array`.
    """
    # from http://stackoverflow.com/a/20785149/732596

    index_sorted = np.argsort(known_array)
    known_array_sorted = known_array[index_sorted]

    idx1 = np.searchsorted(known_array_sorted, test_array)
    idx2 = np.clip(idx1 - 1, 0, len(known_array_sorted)-1)
    idx3 = np.clip(idx1,     0, len(known_array_sorted)-1)

    diff1 = known_array_sorted[idx3] - test_array
    diff2 = test_array - known_array_sorted[idx2]

    indices = index_sorted[np.where(diff1 <= diff2, idx3, idx2)]
    residuals = test_array - known_array[indices]
    return indices, residuals

def container_to_string(container, sep='_'):
    if isinstance(container, basestring):
        string = container
    else:
        try:
            string = sep.join([str(element) for element in container])
        except TypeError:
            string = str(container)
    return string

def simplest_type_for(values):
    n_values = len(values)
    if n_values == 1:
        return list(values)[0]
    elif n_values == 0:
        return
    else:
        return tuple(values)

def flatten_2d_list(list2d):
    list1d = []
    for item in list2d:
        if isinstance(item, basestring):
            list1d.append(item)
        else:
            try:
                len(item)
            except TypeError:
                list1d.append(item)
            else:
                list1d.extend(item)
    return list1d

def get_index(data):
    """
    Parameters
    ----------
    data : pandas.DataFrame or Series or DatetimeIndex

    Returns
    -------
    index : the index for the DataFrame or Series
    """
    if isinstance(data, (pd.DataFrame, pd.Series)):
        index = data.index
    elif isinstance(data, pd.DatetimeIndex):
        index = data
    else:
        raise TypeError('wrong type for `data`.')
    return index

def convert_to_timestamp(t):
    """
    Parameters
    ----------
    t : str or pd.Timestamp or datetime or None

    Returns
    -------
    pd.Timestamp or None
    """
    return None if t is None else pd.Timestamp(t)

def get_module_directory():
    # Taken from http://stackoverflow.com/a/6098238/732596
    path_to_this_file = dirname(getfile(currentframe()))
    if not isdir(path_to_this_file):
        encoding = getfilesystemencoding()
        path_to_this_file = dirname(unicode(__file__, encoding))
    if not isdir(path_to_this_file):
        abspath(getsourcefile(lambda _: None))
    if not isdir(path_to_this_file):
        path_to_this_file = getcwd()
    assert isdir(path_to_this_file), path_to_this_file + ' is not a directory'
    return path_to_this_file

def dict_to_html(dictionary):
    def format_string(value):
        try:
            if isinstance(value, basestring) and 'http' in value:
                html = '{url}'.format(url=value)
            else:
                html = '{}'.format(value)
        except UnicodeEncodeError:
            html = ''
        return html

    html = '
'
    for key, value in iteritems(dictionary):
        html += '
{}: '.format(key)
        if isinstance(value, list):
            html += '
'
            for item in value:
                html += '
{}
'.format(format_string(item))
            html += '
'
        elif isinstance(value, dict):
            html += dict_to_html(value)
        else:
            html += format_string(value)
        html += '
'
    html += '
'
    return html

def print_dict(dictionary):
    html = dict_to_html(dictionary)
    display(HTML(html))

def offset_alias_to_seconds(alias):
    """Seconds for each period length."""
    dr = pd.date_range('00:00', periods=2, freq=alias)
    return (dr[-1] - dr[0]).total_seconds()

def check_directory_exists(d):
    if not isdir(d):
        raise IOError("Directory '{}' does not exist.".format(d))

def tz_localize_naive(timestamp, tz):
    if tz is None:
        return timestamp
    if timestamp is None or pd.isnull(timestamp):
        return pd.NaT

    timestamp = pd.Timestamp(timestamp)
    if timestamp_is_naive(timestamp):
        timestamp = timestamp.tz_localize('UTC')

    return timestamp.tz_convert(tz)

def get_tz(df):
    index = df.index
    try:
        tz = index.tz
    except AttributeError:
        tz = None
    return tz

def timestamp_is_naive(timestamp):
    """
    Parameters
    ----------
    timestamp : pd.Timestamp or datetime.datetime

    Returns
    -------
    True if `timestamp` is naive (i.e. if it does not have a
    timezone associated with it).  See:
    https://docs.python.org/2/library/datetime.html#available-types
    """
    if timestamp.tzinfo is None:
        return True
    elif timestamp.tzinfo.utcoffset(timestamp) is None:
        return True
    else:
        return False

def get_datastore(filename, format, mode='a'):
    """
    Parameters
    ----------
    filename : string
    format : 'CSV' or 'HDF'
    mode : 'a' (append) or 'w' (write), optional

    Returns
    -------
    metadata : dict
    """
    if filename is not None:
        if format == 'HDF':
            return HDFDataStore(filename, mode)
        elif format == 'CSV':
            return CSVDataStore(filename)
        else:
            raise ValueError('format not recognised')
    else:
        ValueError('filename is None')

def normalise_timestamp(timestamp, freq):
    """Returns the nearest Timestamp to `timestamp` which would be
    in the set of timestamps returned by pd.DataFrame.resample(freq=freq)
    """
    timestamp = pd.Timestamp(timestamp)
    series = pd.Series(np.NaN, index=[timestamp])
    resampled = series.resample(freq).mean()
    return resampled.index[0]

def print_on_line(*strings):
    print(*strings, end="")
    stdout.flush()

def append_or_extend_list(lst, value):
    if value is None:
        return
    elif isinstance(value, list):
        lst.extend(value)
    else:
        lst.append(value)

def convert_to_list(list_like):
    return [] if list_like is None else list(list_like)

def most_common(lst):
    """Returns the most common entry in lst."""
    lst = list(lst)
    counts = {item: lst.count(item) for item in set(lst)}
    counts = pd.Series(counts)
    counts.sort()
    most_common = counts.index[-1]
    return most_common

def capitalise_first_letter(string):
    return string[0].upper() + string[1:]

def capitalise_index(index):
    labels = list(index)
    for i, label in enumerate(labels):
        labels[i] = capitalise_first_letter(label)
    return labels

def capitalise_legend(ax):
    legend_handles = ax.get_legend_handles_labels()
    labels = capitalise_index(legend_handles[1])
    ax.legend(legend_handles[0], labels)
    return ax

def safe_resample(data, **resample_kwargs):
    if data.empty:
        return data

    def _resample_chain(data, all_resample_kwargs):
        """_resample_chain provides a compatibility function for
        deprecated/removed DataFrame.resample kwargs"""

        rule = all_resample_kwargs.pop('rule')
        axis = all_resample_kwargs.pop('axis', None)
        on = all_resample_kwargs.pop('on', None)
        level = all_resample_kwargs.pop('level', None)

        resample_kwargs = {}
        if axis is not None: resample_kwargs['axis'] = axis
        if on is not None: resample_kwargs['on'] = on
        if level is not None: resample_kwargs['level'] = level

        fill_method_str = all_resample_kwargs.pop('fill_method', None)
        if fill_method_str:
            fill_method = lambda df: getattr(df, fill_method_str)()
        else:
            fill_method = lambda df: df

        how_str = all_resample_kwargs.pop('how', None)
        if how_str:
            how = lambda df: getattr(df, how_str)()
        else:
            how = lambda df: df

        if resample_kwargs:
            warnings.warn("Not all resample_kwargs were consumed: {}".format(repr(resample_kwargs)))

        return how(fill_method(data.resample(rule, **resample_kwargs)))

    try:
        if len(data.index.get_duplicates()) > 0:
            warnings.warn("Found duplicate index. Keeping first value")
            data = data[~data.index.duplicated(keep='first')]
        data = _resample_chain(data, resample_kwargs)
    except pytz.AmbiguousTimeError:
        # Work-around for
        # https://github.com/pydata/pandas/issues/10117
        tz = data.index.tz.zone
        data = data.tz_convert('UTC')
        data = _resample_chain(data, resample_kwargs)

        data = data.tz_convert(tz)
    return data
<|endoftext|>