Instruction:
Implement a Python 3 function for
updating passed in fit or index as current fit for the editor (does not affect parent), if no parameters are passed in it sets first fit as current @param: new_fit -> fit object to highlight as selected

Response:
def change_selected(self,new_fit):
        """
        updates passed in fit or index as current fit for the editor (does not affect parent),
        if no parameters are passed in it sets first fit as current
        @param: new_fit -> fit object to highlight as selected
        """
        if len(self.fit_list)==0: return
        if self.search_query and self.parent.current_fit not in [x[0] for x in self.fit_list]: return
        if self.current_fit_index == None:
            if not self.parent.current_fit: return
            for i,(fit,specimen) in enumerate(self.fit_list):
                if fit == self.parent.current_fit:
                    self.current_fit_index = i
                    break
        i = 0
        if isinstance(new_fit, Fit):
            for i, (fit,speci) in enumerate(self.fit_list):
                if fit == new_fit:
                    break
        elif type(new_fit) is int:
            i = new_fit
        elif new_fit != None:
            print(('cannot select fit of type: ' + str(type(new_fit))))
        if self.current_fit_index != None and \
        len(self.fit_list) > 0 and \
        self.fit_list[self.current_fit_index][0] in self.parent.bad_fits:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"")
        else:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"WHITE")
        self.current_fit_index = i
        if self.fit_list[self.current_fit_index][0] in self.parent.bad_fits:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"red")
        else:
            self.logger.SetItemBackgroundColour(self.current_fit_index,"LIGHT BLUE")


Instruction:
Can you implement a function in Python 3 that
focuses the logger on an index 12 entries below i

Response:
def logger_focus(self,i,focus_shift=16):
        """
        focuses the logger on an index 12 entries below i
        @param: i -> index to focus on
        """
        if self.logger.GetItemCount()-1 > i+focus_shift:
            i += focus_shift
        else:
            i = self.logger.GetItemCount()-1
        self.logger.Focus(i)


Instruction:
Implement a Python 3 function for
handling the double click on the listctrl

Response:
def OnClick_listctrl(self, event):
        """
        Edits the logger and the Zeq_GUI parent object to select the fit that was newly selected by a double click
        @param: event -> wx.ListCtrlEvent that triggered this function
        """
        i = event.GetIndex()
        if self.parent.current_fit == self.fit_list[i][0]: return
        self.parent.initialize_CART_rot(self.fit_list[i][1])
        si = self.parent.specimens.index(self.fit_list[i][1])
        self.parent.specimens_box.SetSelection(si)
        self.parent.select_specimen(self.fit_list[i][1])
        self.change_selected(i)
        fi = 0
        while (self.parent.s == self.fit_list[i][1] and i >= 0): i,fi = (i-1,fi+1)
        self.parent.update_fit_box()
        self.parent.fit_box.SetSelection(fi-1)
        self.parent.update_selection()


Instruction:
Explain what the following Python 3 code does
def OnRightClickListctrl(self, event):
        i = event.GetIndex()
        fit,spec = self.fit_list[i][0],self.fit_list[i][1]
        if fit in self.parent.bad_fits:
            if not self.parent.mark_fit_good(fit,spec=spec): return
            if i == self.current_fit_index:
                self.logger.SetItemBackgroundColour(i,"LIGHT BLUE")
            else:
                self.logger.SetItemBackgroundColour(i,"WHITE")
        else:
            if not self.parent.mark_fit_bad(fit): return
            if i == self.current_fit_index:
                self.logger.SetItemBackgroundColour(i,"red")
            else:
                self.logger.SetItemBackgroundColour(i,"red")
        self.parent.calculate_high_levels_data()
        self.parent.plot_high_levels_data()
        self.logger_focus(i)

Response: Function is called when the Zeq_GUI is right clicking the list control.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def on_select_show_box(self,event):
        self.parent.UPPER_LEVEL_SHOW=self.show_box.GetValue()
        self.parent.calculate_high_levels_data()
        self.parent.plot_high_levels_data()

Response: This function is called when the user selects a new type of mean shown on the high levels mean plot.


Instruction:
Can you write a function in Python 3 where it
sets the selected specimen interpretations in the level_names combobox to give the user selections for which interpretations are shown in the logger.

Response:
def on_select_high_level(self,event,called_by_parent=False):
        """
        alters the possible entries in level_names combobox to give the user selections for which specimen interpretations to display in the logger
        @param: event -> the wx.COMBOBOXEVENT that triggered this function
        """
        UPPER_LEVEL=self.level_box.GetValue()

        if UPPER_LEVEL=='sample':
            self.level_names.SetItems(self.parent.samples)
            self.level_names.SetStringSelection(self.parent.Data_hierarchy['sample_of_specimen'][self.parent.s])

        if UPPER_LEVEL=='site':
            self.level_names.SetItems(self.parent.sites)
            self.level_names.SetStringSelection(self.parent.Data_hierarchy['site_of_specimen'][self.parent.s])

        if UPPER_LEVEL=='location':
            self.level_names.SetItems(self.parent.locations)
            self.level_names.SetStringSelection(self.parent.Data_hierarchy['location_of_specimen'][self.parent.s])

        if UPPER_LEVEL=='study':
            self.level_names.SetItems(['this study'])
            self.level_names.SetStringSelection('this study')

        if not called_by_parent:
            self.parent.level_box.SetStringSelection(UPPER_LEVEL)
            self.parent.onSelect_high_level(event,True)

        self.on_select_level_name(event)


Instruction:
Create a Python 3 function for
selecting the specimen interpretatoins in this objects logger

Response:
def on_select_level_name(self,event,called_by_parent=False):
        """
        change this objects specimens_list to control which specimen interpretatoins are displayed in this objects logger
        @param: event -> the wx.ComboBoxEvent that triggered this function
        """
        high_level_name=str(self.level_names.GetValue())

        if self.level_box.GetValue()=='sample':
            self.specimens_list=self.parent.Data_hierarchy['samples'][high_level_name]['specimens']
        elif self.level_box.GetValue()=='site':
            self.specimens_list=self.parent.Data_hierarchy['sites'][high_level_name]['specimens']
        elif self.level_box.GetValue()=='location':
            self.specimens_list=self.parent.Data_hierarchy['locations'][high_level_name]['specimens']
        elif self.level_box.GetValue()=='study':
            self.specimens_list=self.parent.Data_hierarchy['study']['this study']['specimens']

        if not called_by_parent:
            self.parent.level_names.SetStringSelection(high_level_name)
            self.parent.onSelect_level_name(event,True)

        self.specimens_list.sort(key=spec_key_func)
        self.update_editor()


Instruction:
Given the following Python 3 function, write the documentation
def on_select_mean_type_box(self, event):
        new_mean_type = self.mean_type_box.GetValue()
        if new_mean_type == "None":
            self.parent.clear_high_level_pars()
        self.parent.mean_type_box.SetStringSelection(new_mean_type)
        self.parent.onSelect_mean_type_box(event)

Response: set parent Zeq_GUI to reflect change in this box and change the


Instruction:
Write a Python 3 script for
setting parent Zeq_GUI to reflect the change in this box then replot the high level means plot @param: event -> the wx.COMBOBOXEVENT that triggered this function

Response:
def on_select_mean_fit_box(self, event):
        """
        set parent Zeq_GUI to reflect the change in this box then replot the high level means plot
        @param: event -> the wx.COMBOBOXEVENT that triggered this function
        """
        new_mean_fit = self.mean_fit_box.GetValue()
        self.parent.mean_fit_box.SetStringSelection(new_mean_fit)
        self.parent.onSelect_mean_fit_box(event)


Instruction:
How would you implement a function in Python 3 that
adds a new interpretation to each specimen highlighted in logger

Response:
def add_highlighted_fits(self, evnet):
        """
        adds a new interpretation to each specimen highlighted in logger if multiple interpretations are highlighted of the same specimen only one new interpretation is added
        @param: event -> the wx.ButtonEvent that triggered this function
        """

        specimens = []
        next_i = self.logger.GetNextSelected(-1)
        if next_i == -1: return
        while next_i != -1:
            fit,specimen = self.fit_list[next_i]
            if specimen in specimens:
                next_i = self.logger.GetNextSelected(next_i)
                continue
            else: specimens.append(specimen)
            next_i = self.logger.GetNextSelected(next_i)

        for specimen in specimens:
            self.add_fit_to_specimen(specimen)

        self.update_editor()
        self.parent.update_selection()


Instruction:
How would you explain what the following Python 3 function does
def delete_highlighted_fits(self, event):

        next_i = -1
        deleted_items = []
        while True:
            next_i = self.logger.GetNextSelected(next_i)
            if next_i == -1:
                break
            deleted_items.append(next_i)
        deleted_items.sort(reverse=True)
        for item in deleted_items:
            self.delete_entry(index=item)
        self.parent.update_selection()

Response: Delete highlighted fits from the logger and the Zeq_GUI parent object


Instruction:
Can you tell what is the following Python 3 function doing
def delete_entry(self, fit = None, index = None):
        if type(index) == int and not fit:
            fit,specimen = self.fit_list[index]
        if fit and type(index) == int:
            for i, (f,s) in enumerate(self.fit_list):
                if fit == f:
                    index,specimen = i,s
                    break

        if index == self.current_fit_index: self.current_fit_index = None
        if fit not in self.parent.pmag_results_data['specimens'][specimen]:
            print(("cannot remove item (entry #: " + str(index) + ") as it doesn't exist, this is a dumb bug contact devs"))
            self.logger.DeleteItem(index)
            return
        self.parent.pmag_results_data['specimens'][specimen].remove(fit)
        del self.fit_list[index]
        self.logger.DeleteItem(index)

Response: Delete a single entry from the logger of this object.


Instruction:
Can you tell what is the following Python 3 function doing
def apply_changes(self, event):

        new_name = self.name_box.GetLineText(0)
        new_color = self.color_box.GetValue()
        new_tmin = self.tmin_box.GetValue()
        new_tmax = self.tmax_box.GetValue()

        next_i = -1
        changed_i = []
        while True:
            next_i = self.logger.GetNextSelected(next_i)
            if next_i == -1:
                break
            specimen = self.fit_list[next_i][1]
            fit = self.fit_list[next_i][0]
            if new_name:
                if new_name not in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]: fit.name = new_name
            if new_color:
                fit.color = self.color_dict[new_color]
            #testing
            not_both = True
            if new_tmin and new_tmax:
                if fit == self.parent.current_fit:
                    self.parent.tmin_box.SetStringSelection(new_tmin)
                    self.parent.tmax_box.SetStringSelection(new_tmax)
                fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,new_tmin,new_tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type))
                not_both = False
            if new_tmin and not_both:
                if fit == self.parent.current_fit:
                    self.parent.tmin_box.SetStringSelection(new_tmin)
                fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,new_tmin,fit.tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type))
            if new_tmax and not_both:
                if fit == self.parent.current_fit:
                    self.parent.tmax_box.SetStringSelection(new_tmax)
                fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,fit.tmin,new_tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type))
            changed_i.append(next_i)

        offset = 0
        for i in changed_i:
            i -= offset
            v = self.update_logger_entry(i)
            if v == "s":
                offset += 1

        self.parent.update_selection()

Response: Applies the changes in the various attribute boxes of this object to all highlighted fit objects in the GUI.


Instruction:
Write a Python 3 script for
panning or zoom the high equal area

Response:
def pan_zoom_high_equalarea(self,event):
        """
        Uses the toolbar for the canvas to change the function from zoom to pan or pan to zoom
        @param: event -> the wx.MouseEvent that triggered this funciton
        """
        if event.LeftIsDown() or event.ButtonDClick():
            return
        elif self.high_EA_setting == "Zoom":
            self.high_EA_setting = "Pan"
            try: self.toolbar.pan('off')
            except TypeError: pass
        elif self.high_EA_setting == "Pan":
            self.high_EA_setting = "Zoom"
            try: self.toolbar.zoom()
            except TypeError: pass
        else:
            self.high_EA_setting = "Zoom"
            try: self.toolbar.zoom()
            except TypeError: pass


Instruction:
Explain what the following Python 3 code does
def main():
    N, L, D, R = 100, 0., 0., 0
    G2, G3 = 0., 0.
    cnt = 1
    Imax = 0
    if len(sys.argv) != 0 and '-h' in sys.argv:
        print(main.__doc__)
        sys.exit()
    else:
        if '-n' in sys.argv:
            ind = sys.argv.index('-n')
            N = int(sys.argv[ind + 1])
        if '-d' in sys.argv:
            ind = sys.argv.index('-d')
            D = float(sys.argv[ind + 1])
        if '-lat' in sys.argv:
            ind = sys.argv.index('-lat')
            L = float(sys.argv[ind + 1])
        if '-t' in sys.argv:
            ind = sys.argv.index('-t')
            Imax = 1e3 * float(sys.argv[ind + 1])
        if '-rev' in sys.argv:
            R = 1
        if '-G2' in sys.argv:
            ind = sys.argv.index('-G2')
            G2 = float(sys.argv[ind + 1])
        if '-G3' in sys.argv:
            ind = sys.argv.index('-G3')
            G3 = float(sys.argv[ind + 1])
    for k in range(N):
        gh = pmag.mktk03(8, k, G2, G3)  # terms and random seed
        # get a random longitude, between 0 and 359
        lon = random.randint(0, 360)
        vec = pmag.getvec(gh, L, lon)  # send field model and lat to getvec
        if vec[2] >= Imax:
            vec[0] += D
            if k % 2 == 0 and R == 1:
                vec[0] += 180.
                vec[1] = -vec[1]
            if vec[0] >= 360.:
                vec[0] -= 360.
            print('%7.1f %7.1f %8.2f ' % (vec[0], vec[1], vec[2]))

Response:
NAME
        tk03.py

    DESCRIPTION
        generates set of vectors drawn from TK03.gad at given lat and
        rotated about vertical axis by given Dec

    INPUT (COMMAND LINE ENTRY)
    OUTPUT
        dec,  inc, int

    SYNTAX
        tk03.py [command line options] [> OutputFileName]

    OPTIONS
        -n N specify N, default is 100
        -d D specify mean Dec, default is 0
        -lat LAT specify latitude, default is 0
        -rev include reversals
        -t INT  truncates  intensities to >INT uT
        -G2 FRAC  specify average g_2^0 fraction (default is 0)
        -G3 FRAC  specify average g_3^0 fraction (default is 0)


Instruction:
Here you have a function in Python 3, explain what it does
def main():
    N,mean,sigma=100,0,1.
    outfile=""
    if '-h' in sys.argv:
        print(main.__doc__)
        sys.exit()
    else:
        if '-s' in sys.argv:
            ind=sys.argv.index('-s')
            sigma=float(sys.argv[ind+1])
        if '-n' in sys.argv:
            ind=sys.argv.index('-n')
            N=int(sys.argv[ind+1])
        if '-m' in sys.argv:
            ind=sys.argv.index('-m')
            mean=float(sys.argv[ind+1])
        if '-F' in sys.argv:
            ind=sys.argv.index('-F')
            outfile=sys.argv[ind+1]
            out=open(outfile,'w')
    for k in range(N):
        x='%f'%(pmag.gaussdev(mean,sigma))  # send kappa to fshdev
        if outfile=="":
            print(x)
        else:
           out.write(x+'\n')

Response:
NAME gaussian. py
            gaussian. py


Instruction:
Can you implement a function in Python 3 that
names qqunf. py is the main function of the qqunf module. It makes a qqplot from input data against uniform distribution of the current one.

Response:
def main():
    """
    NAME
       qqunf.py

    DESCRIPTION
       makes qq plot from input data against uniform distribution

    SYNTAX
       qqunf.py [command line options]

    OPTIONS
        -h help message
        -f FILE, specify file on command line

    """
    fmt,plot='svg',0
    if '-h' in sys.argv: # check if help is needed
        print(main.__doc__)
        sys.exit() # graceful quit
    elif '-f' in sys.argv: # ask for filename
        ind=sys.argv.index('-f')
        file=sys.argv[ind+1]
        f=open(file,'r')
        input=f.readlines()
    Data=[]
    for line in input:
        line.replace('\n','')
        if '\t' in line:   # read in the data from standard input
            rec=line.split('\t') # split each line on space to get records
        else:
            rec=line.split() # split each line on space to get records
        Data.append(float(rec[0]))

#
    if len(Data) >=10:
        QQ={'unf1':1}
        pmagplotlib.plot_init(QQ['unf1'],5,5)
        pmagplotlib.plot_qq_unf(QQ['unf1'],Data,'QQ-Uniform') # make plot
    else:
        print('you need N> 10')
        sys.exit()
    pmagplotlib.draw_figs(QQ)
    files={}
    for key in list(QQ.keys()):
        files[key]=key+'.'+fmt
    if pmagplotlib.isServer:
        black     = '#000000'
        purple    = '#800080'
        titles={}
        titles['eq']='Equal Area Plot'
        EQ = pmagplotlib.add_borders(EQ,titles,black,purple)
        pmagplotlib.save_plots(QQ,files)
    elif plot==1:
        files['qq']=file+'.'+fmt
        pmagplotlib.save_plots(QQ,files)
    else:
        ans=input(" S[a]ve to save plot, [q]uit without saving:  ")
        if ans=="a": pmagplotlib.save_plots(QQ,files)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def InitUI(self):
        self.main_sizer = wx.BoxSizer(wx.VERTICAL)

        if self.grid_type in self.contribution.tables:
            dataframe = self.contribution.tables[self.grid_type]
        else:
            dataframe = None
        self.grid_builder = GridBuilder(self.contribution, self.grid_type,
                                        self.panel, parent_type=self.parent_type,
                                        reqd_headers=self.reqd_headers,
                                        exclude_cols=self.exclude_cols,
                                        huge=self.huge)

        self.grid = self.grid_builder.make_grid()
        self.grid.InitUI()

        ## Column management buttons
        self.add_cols_button = wx.Button(self.panel, label="Add additional columns",
                                         name='add_cols_btn',
                                         size=(170, 20))
        self.Bind(wx.EVT_BUTTON, self.on_add_cols, self.add_cols_button)
        self.remove_cols_button = wx.Button(self.panel, label="Remove columns",
                                            name='remove_cols_btn',
                                            size=(170, 20))

        self.Bind(wx.EVT_BUTTON, self.on_remove_cols, self.remove_cols_button)

        ## Row management buttons
        self.remove_row_button = wx.Button(self.panel, label="Remove last row",
                                           name='remove_last_row_btn')
        self.Bind(wx.EVT_BUTTON, self.on_remove_row, self.remove_row_button)
        many_rows_box = wx.BoxSizer(wx.HORIZONTAL)
        self.add_many_rows_button = wx.Button(self.panel, label="Add row(s)",
                                              name='add_many_rows_btn')
        self.rows_spin_ctrl = wx.SpinCtrl(self.panel, value='1', initial=1,
                                          name='rows_spin_ctrl')
        many_rows_box.Add(self.add_many_rows_button, flag=wx.ALIGN_CENTRE)
        many_rows_box.Add(self.rows_spin_ctrl)
        self.Bind(wx.EVT_BUTTON, self.on_add_rows, self.add_many_rows_button)

        self.deleteRowButton = wx.Button(self.panel, id=-1,
                                         label='Delete selected row(s)',
                                         name='delete_row_btn')
        self.Bind(wx.EVT_BUTTON, lambda event: self.on_remove_row(event, False), self.deleteRowButton)
        self.deleteRowButton.Disable()

        # measurements table should not be able to add new rows
        # that should be done elsewhere
        if self.huge:
            self.add_many_rows_button.Disable()
            self.rows_spin_ctrl.Disable()
            self.remove_row_button.Disable()
            # can't remove cols (seg fault), but can add them
            #self.add_cols_button.Disable()
            self.remove_cols_button.Disable()

        ## Data management buttons
        self.importButton = wx.Button(self.panel, id=-1,
                                      label='Import MagIC-format file',
                                      name='import_btn')
        self.Bind(wx.EVT_BUTTON, self.onImport, self.importButton)
        self.exitButton = wx.Button(self.panel, id=-1,
                                    label='Save and close grid',
                                    name='save_and_quit_btn')
        self.Bind(wx.EVT_BUTTON, self.onSave, self.exitButton)
        self.cancelButton = wx.Button(self.panel, id=-1, label='Cancel',
                                      name='cancel_btn')
        self.Bind(wx.EVT_BUTTON, self.onCancelButton, self.cancelButton)
        self.Bind(wx.EVT_CLOSE, self.onCancelButton)

        ## Input/output buttons
        self.copyButton = wx.Button(self.panel, id=-1,
                                     label="Start copy mode",
                                     name="copy_mode_btn")
        self.Bind(wx.EVT_BUTTON, self.onCopyMode, self.copyButton)
        self.selectAllButton = wx.Button(self.panel, id=-1,
                                         label="Copy all cells",
                                         name="select_all_btn")
        self.Bind(wx.EVT_BUTTON, self.onSelectAll, self.selectAllButton)
        self.copySelectionButton = wx.Button(self.panel, id=-1,
                                         label="Copy selected cells",
                                         name="copy_selection_btn")
        self.Bind(wx.EVT_BUTTON, self.onCopySelection, self.copySelectionButton)
        self.copySelectionButton.Disable()

        ## Help message and button
        # button
        self.toggle_help_btn = wx.Button(self.panel, id=-1, label="Show help",
                                         name='toggle_help_btn')
        self.Bind(wx.EVT_BUTTON, self.toggle_help, self.toggle_help_btn)
        # message
        self.help_msg_boxsizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, name='help_msg_boxsizer'), wx.VERTICAL)

        if self.grid_type == 'measurements':
            self.default_msg_text = "Edit measurements here.\nIn general, measurements should be imported directly into Pmag GUI,\nwhich has protocols for converting many lab formats into the MagIC format.\nIf we are missing your particular lab format, please let us know: https://github.com/PmagPy/PmagPy/issues.\nThis grid is just meant for looking at your measurements and doing small edits.\nCurrently, you can't add/remove rows here.  You can add columns and edit cell values."
        else:
            self.default_msg_text = 'Edit {} here.\nYou can add or remove both rows and columns, however required columns may not be deleted.\nControlled vocabularies are indicated by **, and will have drop-down-menus.\nSuggested vocabularies are indicated by ^^, and also have drop-down-menus.\nTo edit all values in a column, click the column header.\nYou can cut and paste a block of cells from an Excel-like file.\nJust click the top left cell and use command "v".'.format(self.grid_type)
        txt = ''
        if self.grid_type == 'locations':
            txt = '\n\nNote: you can fill in location start/end latitude/longitude here.\nHowever, if you add sites in step 2, the program will calculate those values automatically,\nbased on site latitudes/logitudes.\nThese values will be written to your upload file.'
        if self.grid_type == 'samples':
            txt = "\n\nNote: you can fill in lithology, class, and type for each sample here.\nHowever, if the sample's class, lithology, and type are the same as its parent site,\nthose values will propagate down, and will be written to your sample file automatically."
        if self.grid_type == 'specimens':
            txt = "\n\nNote: you can fill in lithology, class, and type for each specimen here.\nHowever, if the specimen's class, lithology, and type are the same as its parent sample,\nthose values will propagate down, and will be written to your specimen file automatically."
        if self.grid_type == 'ages':
            txt = "\n\nNote: only ages for which you provide data will be written to your upload file."
        self.default_msg_text += txt
        self.msg_text = wx.StaticText(self.panel, label=self.default_msg_text,
                                      style=wx.TE_CENTER, name='msg text')
        self.help_msg_boxsizer.Add(self.msg_text)
        self.help_msg_boxsizer.ShowItems(False)

        ## Code message and button
        # button
        self.toggle_codes_btn = wx.Button(self.panel, id=-1,
                                          label="Show method codes",
                                          name='toggle_codes_btn')
        self.Bind(wx.EVT_BUTTON, self.toggle_codes, self.toggle_codes_btn)
        # message
        self.code_msg_boxsizer = pw.MethodCodeDemystifier(self.panel, self.contribution.vocab)
        self.code_msg_boxsizer.ShowItems(False)

        ## Add content to sizers
        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        col_btn_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Columns',
                                                      name='manage columns'), wx.VERTICAL)
        row_btn_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Rows',
                                                      name='manage rows'), wx.VERTICAL)
        self.main_btn_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Manage data',
                                                            name='manage data'), wx.VERTICAL)
        input_output_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='In/Out',
                                                           name='manage in out'), wx.VERTICAL)
        col_btn_vbox.Add(self.add_cols_button, flag=wx.ALL, border=5)
        col_btn_vbox.Add(self.remove_cols_button, flag=wx.ALL, border=5)
        row_btn_vbox.Add(many_rows_box, flag=wx.ALL, border=5)
        row_btn_vbox.Add(self.remove_row_button, flag=wx.ALL, border=5)
        row_btn_vbox.Add(self.deleteRowButton, flag=wx.ALL, border=5)
        self.main_btn_vbox.Add(self.importButton, flag=wx.ALL, border=5)
        self.main_btn_vbox.Add(self.exitButton, flag=wx.ALL, border=5)
        self.main_btn_vbox.Add(self.cancelButton, flag=wx.ALL, border=5)
        input_output_vbox.Add(self.copyButton, flag=wx.ALL, border=5)
        input_output_vbox.Add(self.selectAllButton, flag=wx.ALL, border=5)
        input_output_vbox.Add(self.copySelectionButton, flag=wx.ALL, border=5)
        self.hbox.Add(col_btn_vbox)
        self.hbox.Add(row_btn_vbox)
        self.hbox.Add(self.main_btn_vbox)
        self.hbox.Add(input_output_vbox)

        #self.panel.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.onLeftClickLabel, self.grid)
        self.grid.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.onLeftClickLabel, self.grid)
        #
        self.Bind(wx.EVT_KEY_DOWN, self.on_key_down)
        self.panel.Bind(wx.EVT_TEXT_PASTE, self.do_fit)
        # add actual data!
        self.grid_builder.add_data_to_grid(self.grid, self.grid_type)
        # fill in some default values
        self.grid_builder.fill_defaults()
        # set scrollbars
        self.grid.set_scrollbars()

        ## this would be a way to prevent editing
        ## some cells in age grid.
        ## with multiple types of ages, though,
        ## this doesn't make much sense
        #if self.grid_type == 'ages':
        #    attr = wx.grid.GridCellAttr()
        #    attr.SetReadOnly(True)
        #    self.grid.SetColAttr(1, attr)

        self.drop_down_menu = drop_down_menus.Menus(self.grid_type, self.contribution, self.grid)
        self.grid_box = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, name='grid container'), wx.VERTICAL)
        self.grid_box.Add(self.grid, 1, flag=wx.ALL|wx.EXPAND, border=5)

        # final layout, set size
        self.main_sizer.Add(self.hbox, flag=wx.ALL|wx.ALIGN_CENTER,#|wx.SHAPED,
                            border=20)
        self.main_sizer.Add(self.toggle_help_btn, 0,
                            flag=wx.BOTTOM|wx.ALIGN_CENTRE,#|wx.SHAPED,
                            border=5)
        self.main_sizer.Add(self.help_msg_boxsizer, 0,
                            flag=wx.BOTTOM|wx.ALIGN_CENTRE,
                            border=10)
        self.main_sizer.Add(self.toggle_codes_btn, 0,
                            flag=wx.BOTTOM|wx.ALIGN_CENTRE,#|wx.SHAPED,
                            border=5)
        self.main_sizer.Add(self.code_msg_boxsizer, 0,
                            flag=wx.BOTTOM|wx.ALIGN_CENTRE,#|wx.SHAPED,
                            border=5)
        self.main_sizer.Add(self.grid_box, 2, flag=wx.ALL|wx.ALIGN_CENTER|wx.EXPAND, border=10)
        self.panel.SetSizer(self.main_sizer)
        panel_sizer = wx.BoxSizer(wx.VERTICAL)
        panel_sizer.Add(self.panel, 1, wx.EXPAND)
        self.SetSizer(panel_sizer)
        panel_sizer.Fit(self)
        ## this keeps sizing correct if the user resizes the window manually
        #self.Bind(wx.EVT_SIZE, self.do_fit)
#        self.Centre()
        self.Show()

Response: Initialize the main UI for the current locale.


Instruction:
Write a Python 3 script for
calling when a key is down in the content area.

Response:
def on_key_down(self, event):
        """
        If user does command v,
        re-size window in case pasting has changed the content size.
        """
        keycode = event.GetKeyCode()
        meta_down = event.MetaDown() or event.GetCmdDown()
        if keycode == 86 and meta_down:
            # treat it as if it were a wx.EVT_TEXT_SIZE
            self.do_fit(event)


Instruction:
Can you implement a function in Python 3 that
toggles help message on help button click.

Response:
def toggle_help(self, event, mode=None):
        """
        Show/hide help message on help button click.
        """
        # if mode == 'open', show no matter what.
        # if mode == 'close', close.  otherwise, change state
        btn = self.toggle_help_btn
        shown = self.help_msg_boxsizer.GetStaticBox().IsShown()
        # if mode is specified, do that mode
        if mode == 'open':
            self.help_msg_boxsizer.ShowItems(True)
            btn.SetLabel('Hide help')
        elif mode == 'close':
            self.help_msg_boxsizer.ShowItems(False)
            btn.SetLabel('Show help')
        # otherwise, simply toggle states
        else:
            if shown:
                self.help_msg_boxsizer.ShowItems(False)
                btn.SetLabel('Show help')
            else:
                self.help_msg_boxsizer.ShowItems(True)
                btn.SetLabel('Hide help')
        self.do_fit(None)


Instruction:
Implement a function in Python 3 to
show or hide method codes explanation widget on button click

Response:
def toggle_codes(self, event):
        """
        Show/hide method code explanation widget on button click
        """
        btn = event.GetEventObject()
        if btn.Label == 'Show method codes':
            self.code_msg_boxsizer.ShowItems(True)
            btn.SetLabel('Hide method codes')
        else:
            self.code_msg_boxsizer.ShowItems(False)
            btn.SetLabel('Show method codes')
        self.do_fit(None)


Instruction:
Can you tell what is the following Python 3 function doing
def remove_col_label(self, event=None, col=None):
        if event:
            col = event.GetCol()
        if not col:
            return
        label = self.grid.GetColLabelValue(col)
        if '**' in label:
            label = label.strip('**')
        elif '^^' in label:
            label = label.strip('^^')
        if label in self.reqd_headers:
            pw.simple_warning("That header is required, and cannot be removed")
            return False
        else:
            print('That header is not required:', label)
            # remove column from wxPython grid
            self.grid.remove_col(col)
            # remove column from DataFrame if present
            if self.grid_type in self.contribution.tables:
                if label in self.contribution.tables[self.grid_type].df.columns:
                    del self.contribution.tables[self.grid_type].df[label]
        # causes resize on each column header delete
        # can leave this out if we want.....
        self.main_sizer.Fit(self)

Response: remove column from grid


Instruction:
Given the following Python 3 function, write the documentation
def on_add_cols(self, event):
        col_labels = self.grid.col_labels
        dia = pw.ChooseOne(self, yes="Add single columns", no="Add groups")
        result1 = dia.ShowModal()
        if result1 == wx.ID_CANCEL:
            return
        elif result1 == wx.ID_YES:
            items = sorted([col_name for col_name in self.dm.index if col_name not in col_labels])
            dia = pw.HeaderDialog(self, 'columns to add',
                                  items1=list(items), groups=[])
            dia.Centre()
            result2 = dia.ShowModal()
        else:
            groups = self.dm['group'].unique()
            dia = pw.HeaderDialog(self, 'groups to add',
                                  items1=list(groups), groups=True)
            dia.Centre()
            result2 = dia.ShowModal()
        new_headers = []
        if result2 == 5100:
            new_headers = dia.text_list
        # if there is nothing to add, quit
        if not new_headers:
            return
        if result1 == wx.ID_YES:
            # add individual headers
            errors = self.add_new_grid_headers(new_headers)
        else:
            # add header groups
            errors = self.add_new_header_groups(new_headers)
        if errors:
            errors_str = ', '.join(errors)
            pw.simple_warning('You are already using the following headers: {}\nSo they will not be added'.format(errors_str))

        # problem: if widgets above the grid are too wide,
        # the grid does not re-size when adding columns
        # awkward solution (causes flashing):
        if self.grid.GetWindowStyle() != wx.DOUBLE_BORDER:
            self.grid.SetWindowStyle(wx.DOUBLE_BORDER)
        self.main_sizer.Fit(self)
        self.grid.SetWindowStyle(wx.NO_BORDER)
        self.Centre()
        self.main_sizer.Fit(self)
        #
        self.grid.changes = set(range(self.grid.GetNumberRows()))
        dia.Destroy()

Response: Show simple dialog that allows user to add a new column name


Instruction:
Write a Python 3 function that can
add new header groups to the compile list of all headers belonging to all specified groups return the list of errors that are already included

Response:
def add_new_header_groups(self, groups):
        """
        compile list of all headers belonging to all specified groups
        eliminate all headers that are already included
        add any req'd drop-down menus
        return errors
        """
        already_present = []
        for group in groups:
            col_names = self.dm[self.dm['group'] == group].index
            for col in col_names:
                if col not in self.grid.col_labels:
                    col_number = self.grid.add_col(col)
                    # add to appropriate headers list
                    # add drop down menus for user-added column
                    if col in self.contribution.vocab.vocabularies:
                        self.drop_down_menu.add_drop_down(col_number, col)
                    elif col in self.contribution.vocab.suggested:
                        self.drop_down_menu.add_drop_down(col_number, col)
                    elif col in ['specimen', 'sample', 'site', 'location',
                                 'specimens', 'samples', 'sites']:
                        self.drop_down_menu.add_drop_down(col_number, col)
                    elif col == 'experiments':
                        self.drop_down_menu.add_drop_down(col_number, col)
                    if col == "method_codes":
                        self.drop_down_menu.add_method_drop_down(col_number, col)
                else:
                    already_present.append(col)
        return already_present


Instruction:
Can you generate the documentation for the following Python 3 function
def add_new_grid_headers(self, new_headers):
        already_present = []
        for name in new_headers:
            if name:
                if name not in self.grid.col_labels:
                    col_number = self.grid.add_col(name)
                    # add to appropriate headers list
                    # add drop down menus for user-added column
                    if name in self.contribution.vocab.vocabularies:
                        self.drop_down_menu.add_drop_down(col_number, name)
                    elif name in self.contribution.vocab.suggested:
                        self.drop_down_menu.add_drop_down(col_number, name)
                    elif name in ['specimen', 'sample', 'site',
                                  'specimens', 'samples', 'sites']:
                        self.drop_down_menu.add_drop_down(col_number, name)
                    elif name == 'experiments':
                        self.drop_down_menu.add_drop_down(col_number, name)
                    if name == "method_codes":
                        self.drop_down_menu.add_method_drop_down(col_number, name)
                else:
                    already_present.append(name)
                    #pw.simple_warning('You are already using column header: {}'.format(name))
        return already_present

Response: Add in all user - added headers.


Instruction:
Write a Python 3 function for
adding rows to grid

Response:
def on_add_rows(self, event):
        """
        add rows to grid
        """
        num_rows = self.rows_spin_ctrl.GetValue()
        #last_row = self.grid.GetNumberRows()
        for row in range(num_rows):
            self.grid.add_row()
            #if not self.grid.changes:
            #    self.grid.changes = set([])
            #self.grid.changes.add(last_row)
            #last_row += 1
        self.main_sizer.Fit(self)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def on_remove_row(self, event, row_num=-1):
        text = "Are you sure?  If you select delete you won't be able to retrieve these rows..."
        dia = pw.ChooseOne(self, "Yes, delete rows", "Leave rows for now", text)
        dia.Centre()
        result = dia.ShowModal()
        if result == wx.ID_NO:
            return
        default = (255, 255, 255, 255)
        if row_num == -1:
            # unhighlight any selected rows:
            for row in self.selected_rows:
                attr = wx.grid.GridCellAttr()
                attr.SetBackgroundColour(default)
                self.grid.SetRowAttr(row, attr)
            row_num = self.grid.GetNumberRows() - 1
            self.deleteRowButton.Disable()
            self.selected_rows = {row_num}
        # remove row(s) from the contribution
        df = self.contribution.tables[self.grid_type].df
        row_nums = list(range(len(df)))
        df = df.iloc[[i for i in row_nums if i not in self.selected_rows]]
        self.contribution.tables[self.grid_type].df = df
        # now remove row(s) from grid
        # delete rows, adjusting the row # appropriately as you delete
        for num, row in enumerate(self.selected_rows):
            row -= num
            if row < 0:
                row = 0
            self.grid.remove_row(row)
            attr = wx.grid.GridCellAttr()
            attr.SetBackgroundColour(default)
            self.grid.SetRowAttr(row, attr)
        # reset the grid
        self.selected_rows = set()
        self.deleteRowButton.Disable()
        self.grid.Refresh()
        self.main_sizer.Fit(self)

Response: Remove specified grid row from the contribution.


Instruction:
How would you explain what the following Python 3 function does
def onLeftClickLabel(self, event):
        if event.Col == -1 and event.Row == -1:
            pass
        if event.Row < 0:
            if self.remove_cols_mode:
                self.remove_col_label(event)
            else:
                self.drop_down_menu.on_label_click(event)
        else:
            if event.Col < 0  and self.grid_type != 'age':
                self.onSelectRow(event)

Response: Called when the user clicks on a label.


Instruction:
Implement a function in Python 3 to
import a MagIC - format file and save it to disk

Response:
def onImport(self, event):
        """
        Import a MagIC-format file
        """
        if self.grid.changes:
            print("-W- Your changes will be overwritten...")
            wind = pw.ChooseOne(self, "Import file anyway", "Save grid first",
                                "-W- Your grid has unsaved changes which will be overwritten if you import a file now...")
            wind.Centre()
            res = wind.ShowModal()
            # save grid first:
            if res == wx.ID_NO:
                self.onSave(None, alert=True, destroy=False)
                # reset self.changes
                self.grid.changes = set()

        openFileDialog = wx.FileDialog(self, "Open MagIC-format file", self.WD, "",
                                       "MagIC file|*.*", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        result = openFileDialog.ShowModal()
        if result == wx.ID_OK:
            # get filename
            filename = openFileDialog.GetPath()
            # make sure the dtype is correct
            f = open(filename)
            line = f.readline()
            if line.startswith("tab"):
                delim, dtype = line.split("\t")
            else:
                delim, dtype = line.split("")
            f.close()
            dtype = dtype.strip()
            if (dtype != self.grid_type) and (dtype + "s" != self.grid_type):
                text = "You are currently editing the {} grid, but you are trying to import a {} file.\nPlease open the {} grid and then re-try this import.".format(self.grid_type, dtype, dtype)
                pw.simple_warning(text)
                return
            # grab old data for concatenation
            if self.grid_type in self.contribution.tables:
                old_df_container = self.contribution.tables[self.grid_type]
            else:
                old_df_container = None
            old_col_names = self.grid.col_labels
            # read in new file and update contribution
            df_container = cb.MagicDataFrame(filename, dmodel=self.dm,
                                             columns=old_col_names)
            # concatenate if possible
            if not isinstance(old_df_container, type(None)):
                df_container.df = pd.concat([old_df_container.df, df_container.df],
                                            axis=0, sort=True)
            self.contribution.tables[df_container.dtype] = df_container
            self.grid_builder = GridBuilder(self.contribution, self.grid_type,
                                            self.panel, parent_type=self.parent_type,
                                            reqd_headers=self.reqd_headers)
            # delete old grid
            self.grid_box.Hide(0)
            self.grid_box.Remove(0)
            # create new, updated grid
            self.grid = self.grid_builder.make_grid()
            self.grid.InitUI()
            # add data to new grid
            self.grid_builder.add_data_to_grid(self.grid, self.grid_type)
            # add new grid to sizer and fit everything
            self.grid_box.Add(self.grid, flag=wx.ALL, border=5)
            self.main_sizer.Fit(self)
            self.Centre()
            # add any needed drop-down-menus
            self.drop_down_menu = drop_down_menus.Menus(self.grid_type,
                                                        self.contribution,
                                                        self.grid)
            # done!
        return


Instruction:
Explain what the following Python 3 code does
def onCancelButton(self, event):
        if self.grid.changes:
            dlg1 = wx.MessageDialog(self, caption="Message:",
                                    message="Are you sure you want to exit this grid?\nYour changes will not be saved.\n ",
                                    style=wx.OK|wx.CANCEL)
            result = dlg1.ShowModal()
            if result == wx.ID_OK:
                dlg1.Destroy()
                self.Destroy()
        else:
            self.Destroy()
        if self.main_frame:
            self.main_frame.Show()
            self.main_frame.Raise()

Response: Quit grid with warning if unsaved changes present


Instruction:
How would you implement a function in Python 3 that
saves grid data and alert user

Response:
def onSave(self, event, alert=False, destroy=True):
        """
        Save grid data
        """
        # tidy up drop_down menu
        if self.drop_down_menu:
            self.drop_down_menu.clean_up()
        # then save actual data
        self.grid_builder.save_grid_data()
        if not event and not alert:
            return
        # then alert user
        wx.MessageBox('Saved!', 'Info',
                      style=wx.OK | wx.ICON_INFORMATION)
        if destroy:
            self.Destroy()


Instruction:
How would you code a function in Python 3 to
set self. df_slice based on user s selection

Response:
def onDragSelection(self, event):
        """
        Set self.df_slice based on user's selection
        """
        if self.grid.GetSelectionBlockTopLeft():
            #top_left = self.grid.GetSelectionBlockTopLeft()
            #bottom_right = self.grid.GetSelectionBlockBottomRight()
            # awkward hack to fix wxPhoenix memory problem, (Github issue #221)
            bottom_right = eval(repr(self.grid.GetSelectionBlockBottomRight()).replace("GridCellCoordsArray: ", "").replace("GridCellCoords", ""))
            top_left = eval(repr(self.grid.GetSelectionBlockTopLeft()).replace("GridCellCoordsArray: ", "").replace("GridCellCoords", ""))
            #
            top_left = top_left[0]
            bottom_right = bottom_right[0]
        else:
            return
        # GetSelectionBlock returns (row, col)
        min_col = top_left[1]
        max_col = bottom_right[1]
        min_row = top_left[0]
        max_row = bottom_right[0]
        self.df_slice = self.contribution.tables[self.grid_type].df.iloc[min_row:max_row+1, min_col:max_col+1]


Instruction:
Can you generate a brief explanation for the following Python 3 code
def onKey(self, event):
        if event.CmdDown() or event.ControlDown():
            if event.GetKeyCode() == 67:
                self.onCopySelection(None)

Response: Copy selection if control down and c key code 67


Instruction:
Can you generate the documentation for the following Python 3 function
def onSelectAll(self, event):
        # do clean up here!!!
        if self.drop_down_menu:
            self.drop_down_menu.clean_up()
        # save all grid data
        self.grid_builder.save_grid_data()
        df = self.contribution.tables[self.grid_type].df
        # write df to clipboard for pasting
        # header arg determines whether columns are taken
        # index arg determines whether index is taken
        pd.DataFrame.to_clipboard(df, header=False, index=False)
        print('-I- You have copied all cells! You may paste them into a text document or spreadsheet using Command v.')

Response: Select all grid and copies it to the Clipboard


Instruction:
Implement a function in Python 3 to
copy selection to the Clipboard

Response:
def onCopySelection(self, event):
        """
        Copies self.df_slice to the Clipboard if slice exists
        """
        if self.df_slice is not None:
            pd.DataFrame.to_clipboard(self.df_slice, header=False, index=False)
            self.grid.ClearSelection()
            self.df_slice = None
            print('-I- You have copied the selected cells.  You may paste them into a text document or spreadsheet using Command v.')
        else:
            print('-W- No cells were copied! You must highlight a selection cells before hitting the copy button.  You can do this by clicking and dragging, or by using the Shift key and click.')


Instruction:
Can you generate a brief explanation for the following Python 3 code
def make_grid(self):
        changes = None
        # if there is a MagicDataFrame, extract data from it
        if isinstance(self.magic_dataframe, cb.MagicDataFrame):
            # get columns and reorder slightly
            col_labels = list(self.magic_dataframe.df.columns)
            for ex_col in self.exclude_cols:
                col_labels.pop(ex_col)
            if self.grid_type == 'ages':
                levels = ['specimen', 'sample', 'site', 'location']
                for label in levels[:]:
                    if label in col_labels:
                        col_labels.remove(label)
                    else:
                        levels.remove(label)
                col_labels[:0] = levels
            else:
                if self.parent_type:
                    if self.parent_type[:-1] in col_labels:
                        col_labels.remove(self.parent_type[:-1])
                    col_labels[:0] = [self.parent_type[:-1]]
                if self.grid_type[:-1] in col_labels:
                    col_labels.remove(self.grid_type[:-1])
                col_labels[:0] = (self.grid_type[:-1],)
            for col in col_labels:
                if col not in self.magic_dataframe.df.columns:
                    self.magic_dataframe.df[col] = None
            self.magic_dataframe.df = self.magic_dataframe.df[col_labels]
            self.magic_dataframe.sort_dataframe_cols()
            col_labels = list(self.magic_dataframe.df.columns)
            row_labels = self.magic_dataframe.df.index
            # make sure minimum defaults are present
            for header in self.reqd_headers:
                if header not in col_labels:
                    changes = set([1])
                    col_labels.append(header)
        # if there is no pre-existing MagicDataFrame,
        # make a blank grid with do some defaults:
        else:
            # default headers
            #col_labels = list(self.data_model.get_headers(self.grid_type, 'Names'))
            #col_labels[:0] = self.reqd_headers
            col_labels = list(self.reqd_headers)
            if self.grid_type in ['specimens', 'samples', 'sites']:
                col_labels.extend(['age', 'age_sigma'])
            ## use the following line if you want sorted column labels:
            #col_labels = sorted(set(col_labels))
            # defaults are different for ages
            if self.grid_type == 'ages':
                levels = ['specimen', 'sample', 'site', 'location']
                for label in levels:
                    if label in col_labels:
                        col_labels.remove(label)
                col_labels[:0] = levels
            else:
                if self.parent_type:
                    col_labels.remove(self.parent_type[:-1])
                    col_labels[:0] = [self.parent_type[:-1]]
                col_labels.remove(self.grid_type[:-1])
                col_labels[:0] = [self.grid_type[:-1]]
        # make sure all reqd cols are in magic_dataframe
        for col in col_labels:
            if col not in self.magic_dataframe.df.columns:
                self.magic_dataframe.df[col] = None
        # make the grid
        if not self.huge:
            grid = magic_grid.MagicGrid(parent=self.panel, name=self.grid_type,
                                        row_labels=[], col_labels=col_labels)
        # make the huge grid
        else:
            row_labels = self.magic_dataframe.df.index
            grid = magic_grid.HugeMagicGrid(parent=self.panel, name=self.grid_type,
                            row_labels=row_labels, col_labels=col_labels)
        grid.do_event_bindings()
        grid.changes = changes

        self.grid = grid
        return grid

Response: make a grid of the magic data


Instruction:
How would you implement a function in Python 3 that
adds columns as needed for age and age_unit.

Response:
def add_age_defaults(self):
        """
        Add columns as needed:
        age, age_unit, specimen, sample, site, location.
        """
        if isinstance(self.magic_dataframe, cb.MagicDataFrame):
            for col in ['age', 'age_unit']:
                if col not in self.grid.col_labels:
                    self.grid.add_col(col)
            for level in ['locations', 'sites', 'samples', 'specimens']:
                if level in self.contribution.tables:
                    if level[:-1] not in self.grid.col_labels:
                        self.grid.add_col(level[:-1])


Instruction:
How would you implement a function in Python 3 that
checks to see if the current grid is empty except for default values

Response:
def current_grid_empty(self):
        """
        Check to see if grid is empty except for default values
        """
        empty = True
        # df IS empty if there are no rows
        if not any(self.magic_dataframe.df.index):
            empty = True
        # df is NOT empty if there are at least two rows
        elif len(self.grid.row_labels) > 1:
            empty = False
        # if there is one row, df MIGHT be empty
        else:
            # check all the non-null values
            non_null_vals = [val for val in self.magic_dataframe.df.values[0] if cb.not_null(val, False)]
            for val in non_null_vals:
                if not isinstance(val, str):
                    empty = False
                    break
                # if there are any non-default values, grid is not empty
                if val.lower() not in ['this study', 'g', 'i']:
                    empty = False
                    break
        return empty


Instruction:
Implement a function in Python 3 to
save the grid data in the object self. grid.

Response:
def save_grid_data(self):
        """
        Save grid data in the data object
        """
        if not self.grid.changes:
            print('-I- No changes to save')
            return

        starred_cols = self.grid.remove_starred_labels()
        # locks in value in cell currently edited
        self.grid.SaveEditControlValue()
        # changes is a dict with key values == row number
        if self.grid.changes:
            new_data = self.grid.save_items()
            # HugeMagicGrid will return a pandas dataframe
            if self.huge:
                self.magic_dataframe.df = new_data
            # MagicGrid will return a dictionary with
            # new/updated data that must be incorporated
            # into the dataframe
            else:
                for key in new_data:
                    data = new_data[key]
                    # update the row if it exists already,
                    # otherwise create a new row

                    updated = self.magic_dataframe.update_row(key, data)
                    if not isinstance(updated, pd.DataFrame):
                        if self.grid_type == 'ages':
                            label = key
                        else:
                            label = self.grid_type[:-1]
                        self.magic_dataframe.add_row(label, data,
                                                     self.grid.col_labels)
            # update the contribution with the new dataframe
            self.contribution.tables[self.grid_type] = self.magic_dataframe
            # *** probably don't actually want to write to file, here (but maybe)

            self.contribution.write_table_to_file(self.grid_type)
            #self.magic_dataframe.write_magic_file("{}.txt".format(self.grid_type),
            #                                      self.contribution.directory)
            # propagate age info if age table was edited
            if self.grid_type == 'ages':
                self.contribution.propagate_ages()
            return


Instruction:
Implement a function in Python 3 to
fill in self. grid with default values in certain columns.

Response:
def fill_defaults(self):
        """
        Fill in self.grid with default values in certain columns.
        Only fill in new values if grid is missing those values.
        """
        defaults = {'result_quality': 'g',
                    'result_type': 'i',
                    'orientation_quality': 'g',
                    'citations': 'This study'}
        for col_name in defaults:
            if col_name in self.grid.col_labels:
                # try to grab existing values from contribution
                if self.grid_type in self.contribution.tables:
                    if col_name in self.contribution.tables[self.grid_type].df.columns:
                        old_vals = self.contribution.tables[self.grid_type].df[col_name]
                        # if column is completely filled in, skip
                        if all([cb.not_null(val, False) for val in old_vals]):
                            continue
                        new_val = defaults[col_name]
                        vals = list(np.where((old_vals.notnull()) & (old_vals != ''), old_vals, new_val))
                    else:
                        vals = [defaults[col_name]] * self.grid.GetNumberRows()
                # if values not available in contribution, use defaults
                else:
                    vals = [defaults[col_name]] * self.grid.GetNumberRows()
            # if col_name not present in grid, skip
            else:
                vals = None
            #
            if vals:
                print('-I- Updating column "{}" with default values'.format(col_name))
                if self.huge:
                    self.grid.SetColumnValues(col_name, vals)
                else:
                    col_ind = self.grid.col_labels.index(col_name)
                    for row, val in enumerate(vals):
                        self.grid.SetCellValue(row, col_ind, val)
                        self.grid.changes = set(range(self.grid.GetNumberRows()))


Instruction:
Can you create a Python 3 function that
returns a list of the children of the result_data

Response:
def get_result_children(self, result_data):
        """
        takes in dict in form of {'er_specimen_names': 'name1:name2:name3'}
        and so forth.
        returns lists of specimens, samples, sites, and locations
        """
        specimens, samples, sites, locations = "", "", "", ""
        children = {'specimen': specimens, 'sample': samples,
                    'site': sites, 'location': locations}
        for dtype in children:
            header_name = 'er_' + dtype + '_names'
            if result_data[header_name]:
                children[dtype] = result_data[header_name].split(":")
                # make sure there are no extra spaces in names
                children[dtype] = [child.strip() for child in children[dtype]]

        return children['specimen'], children['sample'], children['site'], children['location']


Instruction:
Can you tell what is the following Python 3 function doing
def main():
# set defaults
    Comps=[] # list of components
    version_num=pmag.get_version()
    args=sys.argv
    DefaultAge=["none"]
    skipdirs,coord,excrit,custom,vgps,average,Iaverage,plotsites,opt=1,0,0,0,0,0,0,0,0
    get_model_lat=0 # this skips VADM calculation altogether, when get_model_lat=1, uses present day
    fmt='svg'
    dir_path="."
    model_lat_file=""
    Caverage=0
    infile='pmag_specimens.txt'
    measfile="magic_measurements.txt"
    sampfile="er_samples.txt"
    sitefile="er_sites.txt"
    agefile="er_ages.txt"
    specout="er_specimens.txt"
    sampout="pmag_samples.txt"
    siteout="pmag_sites.txt"
    resout="pmag_results.txt"
    critout="pmag_criteria.txt"
    instout="magic_instruments.txt"
    sigcutoff,OBJ="",""
    noDir,noInt=0,0
    polarity=0
    coords=['0']
    Dcrit,Icrit,nocrit=0,0,0
    corrections=[]
    nocorrection=['DA-NL','DA-AC','DA-CR']
    priorities=['DA-AC-ARM','DA-AC-TRM'] # priorities for anisotropy correction
# get command line stuff
    if "-h" in args:
        print(main.__doc__)
        sys.exit()
    if '-WD' in args:
        ind=args.index("-WD")
        dir_path=args[ind+1]
    if '-cor' in args:
        ind=args.index('-cor')
        cors=args[ind+1].split(':') # list of required data adjustments
        for cor in cors:
            nocorrection.remove('DA-'+cor)
            corrections.append('DA-'+cor)
    if '-pri' in args:
        ind=args.index('-pri')
        priorities=args[ind+1].split(':') # list of required data adjustments
        for p in priorities:
            p='DA-AC-'+p
    if '-f' in args:
        ind=args.index("-f")
        measfile=args[ind+1]
    if '-fsp' in args:
        ind=args.index("-fsp")
        infile=args[ind+1]
    if '-fsi' in args:
        ind=args.index("-fsi")
        sitefile=args[ind+1]
    if "-crd" in args:
        ind=args.index("-crd")
        coord=args[ind+1]
        if coord=='s':coords=['-1']
        if coord=='g':coords=['0']
        if coord=='t':coords=['100']
        if coord=='b':coords=['0','100']
    if "-usr" in args:
        ind=args.index("-usr")
        user=sys.argv[ind+1]
    else: user=""
    if "-C" in args: Dcrit,Icrit,nocrit=1,1,1 # no selection criteria
    if "-sam" in args: vgps=1 # save sample level VGPS/VADMs
    if "-xSi" in args:
        nositeints=1 # skip site level intensity
    else:
        nositeints=0
    if "-age" in args:
        ind=args.index("-age")
        DefaultAge[0]=args[ind+1]
        DefaultAge.append(args[ind+2])
        DefaultAge.append(args[ind+3])
    Daverage,Iaverage,Caverage=0,0,0
    if "-aD" in args: Daverage=1 # average by sample directions
    if "-aI" in args: Iaverage=1 # average by sample intensities
    if "-aC" in args: Caverage=1 # average all components together ???  why???
    if "-pol" in args: polarity=1 # calculate averages by polarity
    if '-xD' in args:noDir=1
    if '-xI' in args:
        noInt=1
    elif "-fla" in args:
        if '-lat' in args:
            print("you should set a paleolatitude file OR use present day lat - not both")
            sys.exit()
        ind=args.index("-fla")
        model_lat_file=dir_path+'/'+args[ind+1]
        get_model_lat=2
        mlat=open(model_lat_file,'r')
        ModelLats=[]
        for line in mlat.readlines():
            ModelLat={}
            tmp=line.split()
            ModelLat["er_site_name"]=tmp[0]
            ModelLat["site_model_lat"]=tmp[1]
            ModelLat["er_sample_name"]=tmp[0]
            ModelLat["sample_lat"]=tmp[1]
            ModelLats.append(ModelLat)
        get_model_lat=2
    elif '-lat' in args:
        get_model_lat=1
    if "-p" in args:
        plotsites=1
        if "-fmt" in args:
            ind=args.index("-fmt")
            fmt=args[ind+1]
        if noDir==0: # plot by site - set up plot window
            import pmagplotlib
            EQ={}
            EQ['eqarea']=1
            pmagplotlib.plot_init(EQ['eqarea'],5,5) # define figure 1 as equal area projection
            pmagplotlib.plot_net(EQ['eqarea']) # I don't know why this has to be here, but otherwise the first plot never plots...
            pmagplotlib.draw_figs(EQ)
    if '-WD' in args:
        infile=dir_path+'/'+infile
        measfile=dir_path+'/'+measfile
        instout=dir_path+'/'+instout
        sampfile=dir_path+'/'+sampfile
        sitefile=dir_path+'/'+sitefile
        agefile=dir_path+'/'+agefile
        specout=dir_path+'/'+specout
        sampout=dir_path+'/'+sampout
        siteout=dir_path+'/'+siteout
        resout=dir_path+'/'+resout
        critout=dir_path+'/'+critout
    if "-exc" in args: # use existing pmag_criteria file
        if "-C" in args:
            print('you can not use both existing and no criteria - choose either -exc OR -C OR neither (for default)')
            sys.exit()
        crit_data,file_type=pmag.magic_read(critout)
        print("Acceptance criteria read in from ", critout)
    else  : # use default criteria (if nocrit set, then get really loose criteria as default)
        crit_data=pmag.default_criteria(nocrit)
        if nocrit==0:
            print("Acceptance criteria are defaults")
        else:
            print("No acceptance criteria used ")
    accept={}
    for critrec in crit_data:
        for key in list(critrec.keys()):
# need to migrate specimen_dang to specimen_int_dang for intensity data using old format
            if 'IE-SPEC' in list(critrec.keys()) and 'specimen_dang' in list(critrec.keys()) and 'specimen_int_dang' not in list(critrec.keys()):
                critrec['specimen_int_dang']=critrec['specimen_dang']
                del critrec['specimen_dang']
# need to get rid of ron shaars sample_int_sigma_uT
            if 'sample_int_sigma_uT' in list(critrec.keys()):
                critrec['sample_int_sigma']='%10.3e'%(eval(critrec['sample_int_sigma_uT'])*1e-6)
            if key not in list(accept.keys()) and critrec[key]!='':
                accept[key]=critrec[key]
    #
    #
    if "-exc" not in args and "-C" not in args:
        print("args",args)
        pmag.magic_write(critout,[accept],'pmag_criteria')
        print("\n Pmag Criteria stored in ",critout,'\n')
#
# now we're done slow dancing
#
    SiteNFO,file_type=pmag.magic_read(sitefile) # read in site data - has the lats and lons
    SampNFO,file_type=pmag.magic_read(sampfile) # read in site data - has the lats and lons
    height_nfo=pmag.get_dictitem(SiteNFO,'site_height','','F') # find all the sites with height info.
    if agefile !="":AgeNFO,file_type=pmag.magic_read(agefile) # read in the age information
    Data,file_type=pmag.magic_read(infile) # read in specimen interpretations
    IntData=pmag.get_dictitem(Data,'specimen_int','','F') # retrieve specimens with intensity data
    comment,orient="",[]
    samples,sites=[],[]
    for rec in Data: # run through the data filling in missing keys and finding all components, coordinates available
# fill in missing fields, collect unique sample and site names
        if 'er_sample_name' not in list(rec.keys()):
            rec['er_sample_name']=""
        elif rec['er_sample_name'] not in samples:
            samples.append(rec['er_sample_name'])
        if 'er_site_name' not in list(rec.keys()):
            rec['er_site_name']=""
        elif rec['er_site_name'] not in sites:
            sites.append(rec['er_site_name'])
        if 'specimen_int' not in list(rec.keys()):rec['specimen_int']=''
        if 'specimen_comp_name' not in list(rec.keys()) or rec['specimen_comp_name']=="":rec['specimen_comp_name']='A'
        if rec['specimen_comp_name'] not in Comps:Comps.append(rec['specimen_comp_name'])
        rec['specimen_tilt_correction']=rec['specimen_tilt_correction'].strip('\n')
        if "specimen_tilt_correction" not in list(rec.keys()): rec["specimen_tilt_correction"]="-1" # assume sample coordinates
        if rec["specimen_tilt_correction"] not in orient: orient.append(rec["specimen_tilt_correction"])  # collect available coordinate systems
        if "specimen_direction_type" not in list(rec.keys()): rec["specimen_direction_type"]='l'  # assume direction is line - not plane
        if "specimen_dec" not in list(rec.keys()): rec["specimen_direction_type"]=''  # if no declination, set direction type to blank
        if "specimen_n" not in list(rec.keys()): rec["specimen_n"]=''  # put in n
        if "specimen_alpha95" not in list(rec.keys()): rec["specimen_alpha95"]=''  # put in alpha95
        if "magic_method_codes" not in list(rec.keys()): rec["magic_method_codes"]=''
     #
     # start parsing data into SpecDirs, SpecPlanes, SpecInts
    SpecInts,SpecDirs,SpecPlanes=[],[],[]
    samples.sort() # get sorted list of samples and sites
    sites.sort()
    if noInt==0: # don't skip intensities
        IntData=pmag.get_dictitem(Data,'specimen_int','','F') # retrieve specimens with intensity data
        if nocrit==0: # use selection criteria
            for rec in IntData: # do selection criteria
                kill=pmag.grade(rec,accept,'specimen_int')
                if len(kill)==0: SpecInts.append(rec) # intensity record to be included in sample, site calculations
        else:
            SpecInts=IntData[:] # take everything - no selection criteria
    # check for required data adjustments
        if len(corrections)>0 and len(SpecInts)>0:
            for cor in corrections:
                SpecInts=pmag.get_dictitem(SpecInts,'magic_method_codes',cor,'has') # only take specimens with the required corrections
        if len(nocorrection)>0 and len(SpecInts)>0:
            for cor in nocorrection:
                SpecInts=pmag.get_dictitem(SpecInts,'magic_method_codes',cor,'not') # exclude the corrections not specified for inclusion
# take top priority specimen of its name in remaining specimens (only one per customer)
        PrioritySpecInts=[]
        specimens=pmag.get_specs(SpecInts) # get list of uniq specimen names
        for spec in specimens:
            ThisSpecRecs=pmag.get_dictitem(SpecInts,'er_specimen_name',spec,'T') # all the records for this specimen
            if len(ThisSpecRecs)==1:
                PrioritySpecInts.append(ThisSpecRecs[0])
            elif len(ThisSpecRecs)>1: # more than one
                prec=[]
                for p in priorities:
                    ThisSpecRecs=pmag.get_dictitem(SpecInts,'magic_method_codes',p,'has') # all the records for this specimen
                    if len(ThisSpecRecs)>0:prec.append(ThisSpecRecs[0])
                PrioritySpecInts.append(prec[0]) # take the best one
        SpecInts=PrioritySpecInts # this has the first specimen record
    if noDir==0: # don't skip directions
        AllDirs=pmag.get_dictitem(Data,'specimen_direction_type','','F') # retrieve specimens with directed lines and planes
        Ns=pmag.get_dictitem(AllDirs,'specimen_n','','F')  # get all specimens with specimen_n information
        if nocrit!=1: # use selection criteria
            for rec in Ns: # look through everything with specimen_n for "good" data
                kill=pmag.grade(rec,accept,'specimen_dir')
                if len(kill)==0: # nothing killed it
                    SpecDirs.append(rec)
        else: # no criteria
            SpecDirs=AllDirs[:] # take them all
# SpecDirs is now the list of all specimen directions (lines and planes) that pass muster
#
    PmagSamps,SampDirs=[],[] # list of all sample data and list of those that pass the DE-SAMP criteria
    PmagSites,PmagResults=[],[] # list of all site data and selected results
    SampInts=[]
    for samp in samples: # run through the sample names
        if Daverage==1: #  average by sample if desired
           SampDir=pmag.get_dictitem(SpecDirs,'er_sample_name',samp,'T') # get all the directional data for this sample
           if len(SampDir)>0: # there are some directions
               for coord in coords: # step through desired coordinate systems
                   CoordDir=pmag.get_dictitem(SampDir,'specimen_tilt_correction',coord,'T') # get all the directions for this sample
                   if len(CoordDir)>0: # there are some with this coordinate system
                       if Caverage==0: # look component by component
                           for comp in Comps:
                               CompDir=pmag.get_dictitem(CoordDir,'specimen_comp_name',comp,'T') # get all directions from this component
                               if len(CompDir)>0: # there are some
                                   PmagSampRec=pmag.lnpbykey(CompDir,'sample','specimen') # get a sample average from all specimens
                                   PmagSampRec["er_location_name"]=CompDir[0]['er_location_name'] # decorate the sample record
                                   PmagSampRec["er_site_name"]=CompDir[0]['er_site_name']
                                   PmagSampRec["er_sample_name"]=samp
                                   PmagSampRec["er_citation_names"]="This study"
                                   PmagSampRec["er_analyst_mail_names"]=user
                                   PmagSampRec['magic_software_packages']=version_num
                                   if nocrit!=1:PmagSampRec['pmag_criteria_codes']="ACCEPT"
                                   if agefile != "": PmagSampRec= pmag.get_age(PmagSampRec,"er_site_name","sample_inferred_",AgeNFO,DefaultAge)
                                   site_height=pmag.get_dictitem(height_nfo,'er_site_name',PmagSampRec['er_site_name'],'T')
                                   if len(site_height)>0:PmagSampRec["sample_height"]=site_height[0]['site_height'] # add in height if available
                                   PmagSampRec['sample_comp_name']=comp
                                   PmagSampRec['sample_tilt_correction']=coord
                                   PmagSampRec['er_specimen_names']= pmag.get_list(CompDir,'er_specimen_name') # get a list of the specimen names used
                                   PmagSampRec['magic_method_codes']= pmag.get_list(CompDir,'magic_method_codes') # get a list of the methods used
                                   if nocrit!=1: # apply selection criteria
                                       kill=pmag.grade(PmagSampRec,accept,'sample_dir')
                                   else:
                                       kill=[]
                                   if len(kill)==0:
                                       SampDirs.append(PmagSampRec)
                                       if vgps==1: # if sample level VGP info desired, do that now
                                           PmagResRec=pmag.getsampVGP(PmagSampRec,SiteNFO)
                                           if PmagResRec!="":PmagResults.append(PmagResRec)
                                       PmagSamps.append(PmagSampRec)
                       if Caverage==1: # average all components together  basically same as above
                           PmagSampRec=pmag.lnpbykey(CoordDir,'sample','specimen')
                           PmagSampRec["er_location_name"]=CoordDir[0]['er_location_name']
                           PmagSampRec["er_site_name"]=CoordDir[0]['er_site_name']
                           PmagSampRec["er_sample_name"]=samp
                           PmagSampRec["er_citation_names"]="This study"
                           PmagSampRec["er_analyst_mail_names"]=user
                           PmagSampRec['magic_software_packages']=version_num
                           if nocrit!=1:PmagSampRec['pmag_criteria_codes']=""
                           if agefile != "": PmagSampRec= pmag.get_age(PmagSampRec,"er_site_name","sample_inferred_",AgeNFO,DefaultAge)
                           site_height=pmag.get_dictitem(height_nfo,'er_site_name',site,'T')
                           if len(site_height)>0:PmagSampRec["sample_height"]=site_height[0]['site_height'] # add in height if available
                           PmagSampRec['sample_tilt_correction']=coord
                           PmagSampRec['sample_comp_name']= pmag.get_list(CoordDir,'specimen_comp_name') # get components used
                           PmagSampRec['er_specimen_names']= pmag.get_list(CoordDir,'er_specimen_name') # get specimne names averaged
                           PmagSampRec['magic_method_codes']= pmag.get_list(CoordDir,'magic_method_codes') # assemble method codes
                           if nocrit!=1: # apply selection criteria
                               kill=pmag.grade(PmagSampRec,accept,'sample_dir')
                               if len(kill)==0: # passes the mustard
                                   SampDirs.append(PmagSampRec)
                                   if vgps==1:
                                       PmagResRec=pmag.getsampVGP(PmagSampRec,SiteNFO)
                                       if PmagResRec!="":PmagResults.append(PmagResRec)
                           else: # take everything
                               SampDirs.append(PmagSampRec)
                               if vgps==1:
                                   PmagResRec=pmag.getsampVGP(PmagSampRec,SiteNFO)
                                   if PmagResRec!="":PmagResults.append(PmagResRec)
                           PmagSamps.append(PmagSampRec)
        if Iaverage==1: #  average by sample if desired
           SampI=pmag.get_dictitem(SpecInts,'er_sample_name',samp,'T') # get all the intensity data for this sample
           if len(SampI)>0: # there are some
               PmagSampRec=pmag.average_int(SampI,'specimen','sample') # get average intensity stuff
               PmagSampRec["sample_description"]="sample intensity" # decorate sample record
               PmagSampRec["sample_direction_type"]=""
               PmagSampRec['er_site_name']=SampI[0]["er_site_name"]
               PmagSampRec['er_sample_name']=samp
               PmagSampRec['er_location_name']=SampI[0]["er_location_name"]
               PmagSampRec["er_citation_names"]="This study"
               PmagSampRec["er_analyst_mail_names"]=user
               if agefile != "":   PmagSampRec=pmag.get_age(PmagSampRec,"er_site_name","sample_inferred_", AgeNFO,DefaultAge)
               site_height=pmag.get_dictitem(height_nfo,'er_site_name',PmagSampRec['er_site_name'],'T')
               if len(site_height)>0:PmagSampRec["sample_height"]=site_height[0]['site_height'] # add in height if available
               PmagSampRec['er_specimen_names']= pmag.get_list(SampI,'er_specimen_name')
               PmagSampRec['magic_method_codes']= pmag.get_list(SampI,'magic_method_codes')
               if nocrit!=1:  # apply criteria!
                   kill=pmag.grade(PmagSampRec,accept,'sample_int')
                   if len(kill)==0:
                       PmagSampRec['pmag_criteria_codes']="ACCEPT"
                       SampInts.append(PmagSampRec)
                       PmagSamps.append(PmagSampRec)
                   else:PmagSampRec={} # sample rejected
               else: # no criteria
                   SampInts.append(PmagSampRec)
                   PmagSamps.append(PmagSampRec)
                   PmagSampRec['pmag_criteria_codes']=""
               if vgps==1 and get_model_lat!=0 and PmagSampRec!={}: #
                   if get_model_lat==1: # use sample latitude
                       PmagResRec=pmag.getsampVDM(PmagSampRec,SampNFO)
                       del(PmagResRec['model_lat']) # get rid of the model lat key
                   elif get_model_lat==2: # use model latitude
                       PmagResRec=pmag.getsampVDM(PmagSampRec,ModelLats)
                       if PmagResRec!={}:PmagResRec['magic_method_codes']=PmagResRec['magic_method_codes']+":IE-MLAT"
                   if PmagResRec!={}:
                          PmagResRec['er_specimen_names']=PmagSampRec['er_specimen_names']
                          PmagResRec['er_sample_names']=PmagSampRec['er_sample_name']
                          PmagResRec['pmag_criteria_codes']='ACCEPT'
                          PmagResRec['average_int_sigma_perc']=PmagSampRec['sample_int_sigma_perc']
                          PmagResRec['average_int_sigma']=PmagSampRec['sample_int_sigma']
                          PmagResRec['average_int_n']=PmagSampRec['sample_int_n']
                          PmagResRec['vadm_n']=PmagSampRec['sample_int_n']
                          PmagResRec['data_type']='i'
                          PmagResults.append(PmagResRec)
    if len(PmagSamps)>0:
        TmpSamps,keylist=pmag.fillkeys(PmagSamps) # fill in missing keys from different types of records
        pmag.magic_write(sampout,TmpSamps,'pmag_samples') # save in sample output file
        print(' sample averages written to ',sampout)

#
#create site averages from specimens or samples as specified
#
    for site in sites:
        if Daverage==0: key,dirlist='specimen',SpecDirs # if specimen averages at site level desired
        if Daverage==1: key,dirlist='sample',SampDirs # if sample averages at site level desired
        tmp=pmag.get_dictitem(dirlist,'er_site_name',site,'T') # get all the sites with  directions
        tmp1=pmag.get_dictitem(tmp,key+'_tilt_correction',coords[-1],'T') # use only the last coordinate if Caverage==0
        sd=pmag.get_dictitem(SiteNFO,'er_site_name',site,'T') # fish out site information (lat/lon, etc.)
        if len(sd)>0:
            sitedat=sd[0]
            if Caverage==0: # do component wise averaging
                for comp in Comps:
                    siteD=pmag.get_dictitem(tmp1,key+'_comp_name',comp,'T') # get all components comp
                    if len(siteD)>0: # there are some for this site and component name
                        PmagSiteRec=pmag.lnpbykey(siteD,'site',key) # get an average for this site
                        PmagSiteRec['site_comp_name']=comp # decorate the site record
                        PmagSiteRec["er_location_name"]=siteD[0]['er_location_name']
                        PmagSiteRec["er_site_name"]=siteD[0]['er_site_name']
                        PmagSiteRec['site_tilt_correction']=coords[-1]
                        PmagSiteRec['site_comp_name']= pmag.get_list(siteD,key+'_comp_name')
                        if Daverage==1:
                            PmagSiteRec['er_sample_names']= pmag.get_list(siteD,'er_sample_name')
                        else:
                            PmagSiteRec['er_specimen_names']= pmag.get_list(siteD,'er_specimen_name')
        # determine the demagnetization code (DC3,4 or 5) for this site
                        AFnum=len(pmag.get_dictitem(siteD,'magic_method_codes','LP-DIR-AF','has'))
                        Tnum=len(pmag.get_dictitem(siteD,'magic_method_codes','LP-DIR-T','has'))
                        DC=3
                        if AFnum>0:DC+=1
                        if Tnum>0:DC+=1
                        PmagSiteRec['magic_method_codes']= pmag.get_list(siteD,'magic_method_codes')+':'+ 'LP-DC'+str(DC)
                        PmagSiteRec['magic_method_codes'].strip(":")
                        if plotsites==1:
                            print(PmagSiteRec['er_site_name'])
                            pmagplotlib.plot_site(EQ['eqarea'],PmagSiteRec,siteD,key) # plot and list the data
                            pmagplotlib.draw_figs(EQ)
                        PmagSites.append(PmagSiteRec)
            else: # last component only
                siteD=tmp1[:] # get the last orientation system specified
                if len(siteD)>0: # there are some
                    PmagSiteRec=pmag.lnpbykey(siteD,'site',key) # get the average for this site
                    PmagSiteRec["er_location_name"]=siteD[0]['er_location_name'] # decorate the record
                    PmagSiteRec["er_site_name"]=siteD[0]['er_site_name']
                    PmagSiteRec['site_comp_name']=comp
                    PmagSiteRec['site_tilt_correction']=coords[-1]
                    PmagSiteRec['site_comp_name']= pmag.get_list(siteD,key+'_comp_name')
                    PmagSiteRec['er_specimen_names']= pmag.get_list(siteD,'er_specimen_name')
                    PmagSiteRec['er_sample_names']= pmag.get_list(siteD,'er_sample_name')
                    AFnum=len(pmag.get_dictitem(siteD,'magic_method_codes','LP-DIR-AF','has'))
                    Tnum=len(pmag.get_dictitem(siteD,'magic_method_codes','LP-DIR-T','has'))
                    DC=3
                    if AFnum>0:DC+=1
                    if Tnum>0:DC+=1
                    PmagSiteRec['magic_method_codes']= pmag.get_list(siteD,'magic_method_codes')+':'+ 'LP-DC'+str(DC)
                    PmagSiteRec['magic_method_codes'].strip(":")
                    if Daverage==0:PmagSiteRec['site_comp_name']= pmag.get_list(siteD,key+'_comp_name')
                    if plotsites==1:
                        pmagplotlib.plot_site(EQ['eqarea'],PmagSiteRec,siteD,key)
                        pmagplotlib.draw_figs(EQ)
                    PmagSites.append(PmagSiteRec)
        else:
            print('site information not found in er_sites for site, ',site,' site will be skipped')
    for PmagSiteRec in PmagSites: # now decorate each dictionary some more, and calculate VGPs etc. for results table
        PmagSiteRec["er_citation_names"]="This study"
        PmagSiteRec["er_analyst_mail_names"]=user
        PmagSiteRec['magic_software_packages']=version_num
        if agefile != "": PmagSiteRec= pmag.get_age(PmagSiteRec,"er_site_name","site_inferred_",AgeNFO,DefaultAge)
        PmagSiteRec['pmag_criteria_codes']='ACCEPT'
        if 'site_n_lines' in list(PmagSiteRec.keys()) and 'site_n_planes' in list(PmagSiteRec.keys()) and PmagSiteRec['site_n_lines']!="" and PmagSiteRec['site_n_planes']!="":
            if int(PmagSiteRec["site_n_planes"])>0:
                PmagSiteRec["magic_method_codes"]=PmagSiteRec['magic_method_codes']+":DE-FM-LP"
            elif int(PmagSiteRec["site_n_lines"])>2:
                PmagSiteRec["magic_method_codes"]=PmagSiteRec['magic_method_codes']+":DE-FM"
            kill=pmag.grade(PmagSiteRec,accept,'site_dir')
            if len(kill)==0:
                PmagResRec={} # set up dictionary for the pmag_results table entry
                PmagResRec['data_type']='i' # decorate it a bit
                PmagResRec['magic_software_packages']=version_num
                PmagSiteRec['site_description']='Site direction included in results table'
                PmagResRec['pmag_criteria_codes']='ACCEPT'
                dec=float(PmagSiteRec["site_dec"])
                inc=float(PmagSiteRec["site_inc"])
                if 'site_alpha95' in list(PmagSiteRec.keys()) and PmagSiteRec['site_alpha95']!="":
                    a95=float(PmagSiteRec["site_alpha95"])
                else:a95=180.
                sitedat=pmag.get_dictitem(SiteNFO,'er_site_name',PmagSiteRec['er_site_name'],'T')[0] # fish out site information (lat/lon, etc.)
                lat=float(sitedat['site_lat'])
                lon=float(sitedat['site_lon'])
                plong,plat,dp,dm=pmag.dia_vgp(dec,inc,a95,lat,lon) # get the VGP for this site
                if PmagSiteRec['site_tilt_correction']=='-1':C=' (spec coord) '
                if PmagSiteRec['site_tilt_correction']=='0':C=' (geog. coord) '
                if PmagSiteRec['site_tilt_correction']=='100':C=' (strat. coord) '
                PmagResRec["pmag_result_name"]="VGP Site: "+PmagSiteRec["er_site_name"] # decorate some more
                PmagResRec["result_description"]="Site VGP, coord system = "+str(coord)+' component: '+comp
                PmagResRec['er_site_names']=PmagSiteRec['er_site_name']
                PmagResRec['pmag_criteria_codes']='ACCEPT'
                PmagResRec['er_citation_names']='This study'
                PmagResRec['er_analyst_mail_names']=user
                PmagResRec["er_location_names"]=PmagSiteRec["er_location_name"]
                if Daverage==1:
                    PmagResRec["er_sample_names"]=PmagSiteRec["er_sample_names"]
                else:
                    PmagResRec["er_specimen_names"]=PmagSiteRec["er_specimen_names"]
                PmagResRec["tilt_correction"]=PmagSiteRec['site_tilt_correction']
                PmagResRec["pole_comp_name"]=PmagSiteRec['site_comp_name']
                PmagResRec["average_dec"]=PmagSiteRec["site_dec"]
                PmagResRec["average_inc"]=PmagSiteRec["site_inc"]
                PmagResRec["average_alpha95"]=PmagSiteRec["site_alpha95"]
                PmagResRec["average_n"]=PmagSiteRec["site_n"]
                PmagResRec["average_n_lines"]=PmagSiteRec["site_n_lines"]
                PmagResRec["average_n_planes"]=PmagSiteRec["site_n_planes"]
                PmagResRec["vgp_n"]=PmagSiteRec["site_n"]
                PmagResRec["average_k"]=PmagSiteRec["site_k"]
                PmagResRec["average_r"]=PmagSiteRec["site_r"]
                PmagResRec["average_lat"]='%10.4f ' %(lat)
                PmagResRec["average_lon"]='%10.4f ' %(lon)
                if agefile != "": PmagResRec= pmag.get_age(PmagResRec,"er_site_names","average_",AgeNFO,DefaultAge)
                site_height=pmag.get_dictitem(height_nfo,'er_site_name',site,'T')
                if len(site_height)>0:PmagResRec["average_height"]=site_height[0]['site_height']
                PmagResRec["vgp_lat"]='%7.1f ' % (plat)
                PmagResRec["vgp_lon"]='%7.1f ' % (plong)
                PmagResRec["vgp_dp"]='%7.1f ' % (dp)
                PmagResRec["vgp_dm"]='%7.1f ' % (dm)
                PmagResRec["magic_method_codes"]= PmagSiteRec["magic_method_codes"]
                if PmagSiteRec['site_tilt_correction']=='0':PmagSiteRec['magic_method_codes']=PmagSiteRec['magic_method_codes']+":DA-DIR-GEO"
                if PmagSiteRec['site_tilt_correction']=='100':PmagSiteRec['magic_method_codes']=PmagSiteRec['magic_method_codes']+":DA-DIR-TILT"
                PmagSiteRec['site_polarity']=""
                if polarity==1: # assign polarity based on angle of pole lat to spin axis - may want to re-think this sometime
                    angle=pmag.angle([0,0],[0,(90-plat)])
                    if angle <= 55.: PmagSiteRec["site_polarity"]='n'
                    if angle > 55. and angle < 125.: PmagSiteRec["site_polarity"]='t'
                    if angle >= 125.: PmagSiteRec["site_polarity"]='r'
                PmagResults.append(PmagResRec)
    if polarity==1:
        crecs=pmag.get_dictitem(PmagSites,'site_tilt_correction','100','T') # find the tilt corrected data
        if len(crecs)<2:crecs=pmag.get_dictitem(PmagSites,'site_tilt_correction','0','T') # if there aren't any, find the geographic corrected data
        if len(crecs)>2: # if there are some,
            comp=pmag.get_list(crecs,'site_comp_name').split(':')[0] # find the first component
            crecs=pmag.get_dictitem(crecs,'site_comp_name',comp,'T') # fish out all of the first component
            precs=[]
            for rec in crecs:
                precs.append({'dec':rec['site_dec'],'inc':rec['site_inc'],'name':rec['er_site_name'],'loc':rec['er_location_name']})
            polpars=pmag.fisher_by_pol(precs) # calculate average by polarity
            for mode in list(polpars.keys()): # hunt through all the modes (normal=A, reverse=B, all=ALL)
                PolRes={}
                PolRes['er_citation_names']='This study'
                PolRes["pmag_result_name"]="Polarity Average: Polarity "+mode #
                PolRes["data_type"]="a"
                PolRes["average_dec"]='%7.1f'%(polpars[mode]['dec'])
                PolRes["average_inc"]='%7.1f'%(polpars[mode]['inc'])
                PolRes["average_n"]='%i'%(polpars[mode]['n'])
                PolRes["average_r"]='%5.4f'%(polpars[mode]['r'])
                PolRes["average_k"]='%6.0f'%(polpars[mode]['k'])
                PolRes["average_alpha95"]='%7.1f'%(polpars[mode]['alpha95'])
                PolRes['er_site_names']= polpars[mode]['sites']
                PolRes['er_location_names']= polpars[mode]['locs']
                PolRes['magic_software_packages']=version_num
                PmagResults.append(PolRes)

    if noInt!=1 and nositeints!=1:
      for site in sites: # now do intensities for each site
        if plotsites==1:print(site)
        if Iaverage==0: key,intlist='specimen',SpecInts # if using specimen level data
        if Iaverage==1: key,intlist='sample',PmagSamps # if using sample level data
        Ints=pmag.get_dictitem(intlist,'er_site_name',site,'T') # get all the intensities  for this site
        if len(Ints)>0: # there are some
            PmagSiteRec=pmag.average_int(Ints,key,'site') # get average intensity stuff for site table
            PmagResRec=pmag.average_int(Ints,key,'average') # get average intensity stuff for results table
            if plotsites==1: # if site by site examination requested - print this site out to the screen
                for rec in Ints:print(rec['er_'+key+'_name'],' %7.1f'%(1e6*float(rec[key+'_int'])))
                if len(Ints)>1:
                    print('Average: ','%7.1f'%(1e6*float(PmagResRec['average_int'])),'N: ',len(Ints))
                    print('Sigma: ','%7.1f'%(1e6*float(PmagResRec['average_int_sigma'])),'Sigma %: ',PmagResRec['average_int_sigma_perc'])
                input('Press any key to continue\n')
            er_location_name=Ints[0]["er_location_name"]
            PmagSiteRec["er_location_name"]=er_location_name # decorate the records
            PmagSiteRec["er_citation_names"]="This study"
            PmagResRec["er_location_names"]=er_location_name
            PmagResRec["er_citation_names"]="This study"
            PmagSiteRec["er_analyst_mail_names"]=user
            PmagResRec["er_analyst_mail_names"]=user
            PmagResRec["data_type"]='i'
            if Iaverage==0:
                PmagSiteRec['er_specimen_names']= pmag.get_list(Ints,'er_specimen_name') # list of all specimens used
                PmagResRec['er_specimen_names']= pmag.get_list(Ints,'er_specimen_name')
            PmagSiteRec['er_sample_names']= pmag.get_list(Ints,'er_sample_name') # list of all samples used
            PmagResRec['er_sample_names']= pmag.get_list(Ints,'er_sample_name')
            PmagSiteRec['er_site_name']= site
            PmagResRec['er_site_names']= site
            PmagSiteRec['magic_method_codes']= pmag.get_list(Ints,'magic_method_codes')
            PmagResRec['magic_method_codes']= pmag.get_list(Ints,'magic_method_codes')
            kill=pmag.grade(PmagSiteRec,accept,'site_int')
            if nocrit==1 or len(kill)==0:
                b,sig=float(PmagResRec['average_int']),""
                if(PmagResRec['average_int_sigma'])!="":sig=float(PmagResRec['average_int_sigma'])
                sdir=pmag.get_dictitem(PmagResults,'er_site_names',site,'T') # fish out site direction
                if len(sdir)>0 and  sdir[-1]['average_inc']!="": # get the VDM for this record using last average inclination (hope it is the right one!)
                        inc=float(sdir[0]['average_inc']) #
                        mlat=pmag.magnetic_lat(inc) # get magnetic latitude using dipole formula
                        PmagResRec["vdm"]='%8.3e '% (pmag.b_vdm(b,mlat)) # get VDM with magnetic latitude
                        PmagResRec["vdm_n"]=PmagResRec['average_int_n']
                        if 'average_int_sigma' in list(PmagResRec.keys()) and PmagResRec['average_int_sigma']!="":
                            vdm_sig=pmag.b_vdm(float(PmagResRec['average_int_sigma']),mlat)
                            PmagResRec["vdm_sigma"]='%8.3e '% (vdm_sig)
                        else:
                            PmagResRec["vdm_sigma"]=""
                mlat="" # define a model latitude
                if get_model_lat==1: # use present site latitude
                    mlats=pmag.get_dictitem(SiteNFO,'er_site_name',site,'T')
                    if len(mlats)>0: mlat=mlats[0]['site_lat']
                elif get_model_lat==2: # use a model latitude from some plate reconstruction model (or something)
                    mlats=pmag.get_dictitem(ModelLats,'er_site_name',site,'T')
                    if len(mlats)>0: PmagResRec['model_lat']=mlats[0]['site_model_lat']
                    mlat=PmagResRec['model_lat']
                if mlat!="":
                    PmagResRec["vadm"]='%8.3e '% (pmag.b_vdm(b,float(mlat))) # get the VADM using the desired latitude
                    if sig!="":
                        vdm_sig=pmag.b_vdm(float(PmagResRec['average_int_sigma']),float(mlat))
                        PmagResRec["vadm_sigma"]='%8.3e '% (vdm_sig)
                        PmagResRec["vadm_n"]=PmagResRec['average_int_n']
                    else:
                        PmagResRec["vadm_sigma"]=""
                sitedat=pmag.get_dictitem(SiteNFO,'er_site_name',PmagSiteRec['er_site_name'],'T') # fish out site information (lat/lon, etc.)
                if len(sitedat)>0:
                    sitedat=sitedat[0]
                    PmagResRec['average_lat']=sitedat['site_lat']
                    PmagResRec['average_lon']=sitedat['site_lon']
                else:
                    PmagResRec['average_lon']='UNKNOWN'
                    PmagResRec['average_lon']='UNKNOWN'
                PmagResRec['magic_software_packages']=version_num
                PmagResRec["pmag_result_name"]="V[A]DM: Site "+site
                PmagResRec["result_description"]="V[A]DM of site"
                PmagResRec["pmag_criteria_codes"]="ACCEPT"
                if agefile != "": PmagResRec= pmag.get_age(PmagResRec,"er_site_names","average_",AgeNFO,DefaultAge)
                site_height=pmag.get_dictitem(height_nfo,'er_site_name',site,'T')
                if len(site_height)>0:PmagResRec["average_height"]=site_height[0]['site_height']
                PmagSites.append(PmagSiteRec)
                PmagResults.append(PmagResRec)
    if len(PmagSites)>0:
        Tmp,keylist=pmag.fillkeys(PmagSites)
        pmag.magic_write(siteout,Tmp,'pmag_sites')
        print(' sites written to ',siteout)
    else: print("No Site level table")
    if len(PmagResults)>0:
        TmpRes,keylist=pmag.fillkeys(PmagResults)
        pmag.magic_write(resout,TmpRes,'pmag_results')
        print(' results written to ',resout)
    else: print("No Results level table")

Response: main function for pmag_specimens_results_magic. py