Instruction:
Here you have a function in Python 3, explain what it does
def core_depthplot(input_dir_path='.', meas_file='measurements.txt', spc_file='',
                   samp_file='samples.txt', age_file='', sum_file='', wt_file='',
                   depth_scale='core_depth', dmin=-1, dmax=-1, sym='bo',
                   size=5, spc_sym='ro', spc_size=5, meth='', step=0, fmt='svg',
                   pltDec=True, pltInc=True, pltMag=True, pltLine=True, pltSus=True,
                   logit=False, pltTime=False, timescale=None, amin=-1, amax=-1,
                   norm=False, data_model_num=3,location=""):
    """
    depth scale can be 'core_depth' or 'composite_depth' (for data model=3)
    if age file is provided, depth_scale will be set to 'age' by default.
    You must provide at least a measurements,specimens and sample file to plot.

    Parameters
    ----------
    input_dir_path : str, default "."
        file input directory
    meas_file : str, default "measurements.txt"
        input measurements file
    spc_file : str, default ""
        input specimens file
    samp_file : str, default ""
        input samples file
    age_file : str, default ""
        input ages file
    sum_file : str, default ""
        input csv summary file
    wt_file : str, default ""
        input file with weights
    depth_scale : str, default "core_depth"
        ['core_depth', 'composite_depth']
    dmin : number, default -1
        minimum depth to plot (if -1, default to plotting all)
    dmax : number, default -1
        maximum depth to plot (if -1, default to plotting all)
    sym : str, default "bo"
        symbol color and shape, default blue circles
        (see matplotlib documentaiton for more options)
    size : int, defualt 5
        symbol size
    spc_sym : str, default 'ro'
        specimen symbol color and shape, default red circles
        (see matplotlib documentation for more options)
    meth : str, default ""
        method codes, ["LT-NO", "AF", "T", "ARM", "IRM", "X"]
    step : int, default 0
        treatment step for plotting:
            for AF, in mT, for T, in C
    fmt : str, default "svg"
        format for figures, [svg,jpg,png,pdf]
    pltDec : bool, default True
        plot declination
    pltInc : bool, default True
        plot inclination
    pltMag : bool, default True
        plot magnetization
    pltLine : bool, default True
        connect dots with a line
    pltSus : bool, default True
        plot blanket treatment
    logit : bool, default False
        plot magnetization on a log scale
    amin : int, default -1
        minimum time to plot (if -1, default to plotting all)
    amax : int, default -1
        maximum time to plot (if -1, default to plotting all)
    norm : bool, default False
        normalize by weight
    data_model_num : int, default 3
        MagIC data model (please, use data model 3)
    """
    data_model_num = int(data_model_num)
    # replace MagIC 3 defaults with MagIC 2.5 defaults if needed
    if data_model_num == 2 and meas_file == 'measurements.txt':
        meas_file = 'magic_measurements.txt'
    if data_model_num == 2 and samp_file == 'samples.txt':
        samp_file = 'er_samples.txt'
    if data_model_num == 2 and age_file == 'ages.txt':
        age_file = 'er_ages.txt'
    if data_model_num == 2 and depth_scale == "core_depth":
        depth_scale = "sample_core_depth"
    # initialize MagIC 3.0 vs 2.5 column names
    loc_col_name = "location" if data_model_num == 3 else "er_location_name"
    site_col_name = "site" if data_model_num == 3 else "er_site_name"
    samp_col_name = "sample" if data_model_num == 3 else "er_sample_name"
    spec_col_name = "specimen" if data_model_num == 3 else "er_specimen_name"
    meth_col_name = "method_codes" if data_model_num == 3 else "magic_method_codes"
    spec_dec_col_name = "dir_dec" if data_model_num == 3 else "specimen_dec"
    spec_inc_col_name = "dir_inc" if data_model_num == 3 else "specimen_inc"
    avg_weight_col_name = "weight" if data_model_num == 3 else "average_weight"
    spec_weight_col_name = "weight" if data_model_num == 3 else "specimen_weight"
    age_col_name = "age" if data_model_num == 3 else "average_age"
    height_col_name = "height" if data_model_num == 3 else "average_height"
    average_dec_col_name = "dir_dec" if data_model_num == 3 else "average_dec"
    average_inc_col_name = "dir_inc" if data_model_num == 3 else "average_inc"
    # initialize other variables
    width = 10
    Ssym, Ssize = 'cs', 5
    pcol = 3
    pel = 3
    maxInt = -1000
    minInt = 1e10
    maxSuc = -1000
    minSuc = 10000
    main_plot = None
    if size:
        size = int(size)
    if spc_size:
        spc_size = int(spc_size)
    title = ""
    if location:title=location

    # file formats not supported for the moment
    ngr_file = ""  # nothing needed, not implemented fully in original script
    suc_file = ""  # nothing else needed, also was not implemented in original script
    res_file = ""  # need also res_sym, res_size
    wig_file = ""  # if wig_file: pcol+=1; width+=2

    # which plots to make
    if not pltDec:
        pcol -= 1
        pel -= 1
        width -= 2
    if not pltInc:
        pcol -= 1
        pel -= 1
        width -= 2
    if not pltMag:
        pcol -= 1
        pel -= 1
        width -= 2

    # method and step
    if not step or meth == 'LT-NO':
        step = 0
        method = 'LT-NO'
    elif meth == "AF":
        step = round(float(step) * 1e-3, 6)
        method = 'LT-AF-Z'
    elif meth == 'T':
        step = round(float(step) + 273, 6)
        method = 'LT-T-Z'
    elif meth == 'ARM':
        method = 'LT-AF-I'
        step = round(float(step) * 1e-3, 6)
    elif meth == 'IRM':
        method = 'LT-IRM'
        step = round(float(step) * 1e-3, 6)
    # not supporting susceptibility at the moment LJ
    elif meth == 'X':
        method = 'LP-X'
        pcol += 1
        ind = sys.argv.index('-LP')
        if sys.argv[ind+2] == 'mass':
            if data_model_num != 3:
                suc_key = 'measurement_chi_mass'
            else:
                suc_key = 'susc_chi_mass'
        elif sys.argv[ind+2] == 'vol':
            if data_model_num != 3:
                suc_key = 'measurement_chi_volume'
            else:
                suc_key = 'susc_chi_volume'
        else:
            print('error in susceptibility units')
            return False, 'error in susceptibility units'
    else:
        print('method: {} not supported'.format(meth))
        return False, 'method: "{}" not supported'.format(meth)

    if wt_file:
        norm = True

    if dmin and dmax:
        dmin, dmax = float(dmin), float(dmax)
    else:
        dmin, dmax = -1, -1

    if pltTime:
        amin = float(amin)
        amax = float(amax)
        pcol += 1
        width += 2
        if not (amax and timescale):
            return False, "To plot time, you must provide amin, amax, and timescale"

    #
    #
    # read in 3.0 data and translate to 2.5

    if meas_file:
        meas_file = pmag.resolve_file_name(meas_file, input_dir_path)
    if spc_file:
        spc_file = pmag.resolve_file_name(spc_file, input_dir_path)
    if samp_file:
        samp_file = pmag.resolve_file_name(samp_file, input_dir_path)
    if age_file:
        age_file = pmag.resolve_file_name(age_file, input_dir_path)
    if data_model_num == 3:
        fnames = {'specimens': spc_file, 'samples': samp_file,
                  'ages': age_file, 'measurements': meas_file}
        fnames = {k: v for (k, v) in fnames.items() if v}
        con = cb.Contribution(input_dir_path, custom_filenames=fnames)
        for dtype in ['measurements', 'specimens']:
            if dtype not in con.tables:
                print(
                    '-E- You must have a {} file in your input directory ({}) to run core_depthplot'.format(dtype, input_dir_path))
                print('    If needed, you can specify your input directory on the command line with "core_depthplot.py -ID dirname ... "')
                print('    Or with ipmag.core_depthplot(input_dir_path=dirname, ...)')
                # return False, '-E- You must have a {} file in your input directory ({}) to run core_depthplot'.format(dtype, input_dir_path)
        # propagate data to measurements
        con.propagate_name_down('sample', 'measurements')
        con.propagate_name_down('site', 'measurements')

        # propagate depth info from sites --> samples
        con.propagate_cols(
            ['core_depth', 'composite_depth'], 'samples', 'sites')

        if age_file == "":
            # get sample data straight from the contribution
            Samps = []
            if 'samples' in con.tables:
                Samps = con.tables['samples'].convert_to_pmag_data_list()
        else:
            depth_scale = 'age'
            Samps = []
            # get age data from contribution
            if 'ages' in con.tables:
                # we need to get sample in here
                # this doesn't do the trick by itself
                con.propagate_ages()
                con.propagate_cols(['age', 'age_unit'], 'samples', 'sites')
                Samps = con.tables['samples'].convert_to_pmag_data_list()
            age_unit = ""
        if spc_file:
            Specs3 = []
            # get specimen data from contribution
            Specs = []
            if 'specimens' in con.tables:
                Specs = con.tables['specimens'].convert_to_pmag_data_list()

        if res_file:
            warn = '-W- result file option is not currently available for MagIC data model 3'
            print(warn)
            return False, warn
            #Results, file_type = pmag.magic_read(res_file)
        if norm:
            #warn = '-W- norm option is not currently available for MagIC data model 3'
            # print(warn)
            # return False, warn
            Specs3, file_type = pmag.magic_read(wt_file)
            # translate specimen records to 2.5
            ErSpecs = []
            # for spec in Specs3:
            #    ErSpecs.append(map_magic.mapping(spec, spec_magic3_2_magic2_map))
            ErSpecs = Specs3

            print(len(ErSpecs), ' specimens read in from ', wt_file)

        if not os.path.isfile(spc_file):
            if not os.path.isfile(meas_file):
                return False, "You must provide either a magic_measurements file or a pmag_specimens file"
        if not age_file and not samp_file:
            print('-W- You must provide either an age file or a sample file')
            return False, '-W- You must provide either an age file or a sample file'

    # read in 2.5 data
    elif data_model_num == 2:
        if age_file == "":
            if samp_file:
                samp_file = os.path.join(input_dir_path, samp_file)
            Samps, file_type = pmag.magic_read(samp_file)
        else:
            depth_scale = 'age'
            if age_file:
                age_file = os.path.join(input_dir_path, age_file)
            Samps, file_type = pmag.magic_read(age_file)
            age_unit = ""
        if spc_file:
            Specs, file_type = pmag.magic_read(spc_file)
        if res_file:
            Results, file_type = pmag.magic_read(res_file)
        if norm:
            ErSpecs, file_type = pmag.magic_read(wt_file)
            print(len(ErSpecs), ' specimens read in from ', wt_file)

        if not os.path.isfile(spc_file):
            if not os.path.isfile(meas_file):
                return False, "You must provide either a magic_measurements file or a pmag_specimens file"
    else:
        return False, "Invalid data model number: {}".format(str(data_model_num))

    Cores = []
    core_depth_key = "Top depth cored CSF (m)"
    if sum_file:
        # os.path.join(input_dir_path, sum_file)
        sum_file = pmag.resolve_file_name(sum_file, input_dir_path)
        with open(sum_file, 'r') as fin:
            indat = fin.readlines()
        if "Core Summary" in indat[0]:
            headline = 1
        else:
            headline = 0
        keys = indat[headline].replace('\n', '').split(',')
        if "Core Top (m)" in keys:
            core_depth_key = "Core Top (m)"
        if "Top depth cored CSF (m)" in keys:
            core_dpeth_key = "Top depth cored CSF (m)"
        if "Core Label" in keys:
            core_label_key = "Core Label"
        if "Core label" in keys:
            core_label_key = "Core label"
        for line in indat[2:]:
            if 'TOTALS' not in line:
                CoreRec = {}
                for k in range(len(keys)):
                    CoreRec[keys[k]] = line.split(',')[k]
                Cores.append(CoreRec)
        if len(Cores) == 0:
            print('no Core depth information available: import core summary file')
            sum_file = ""
    Data = []
    if 'core_depth' in depth_scale or depth_scale == 'mbsf':
        ylab = "Depth (mbsf)"
        depth_scale = 'core_depth'
    elif depth_scale == 'age':
        ylab = "Age"
    elif 'composite_depth' in depth_scale or depth_scale == 'mcd':
        ylab = "Depth (mcd)"
        depth_scale = 'composite_depth'
    else:
        print('Warning: You have provided unsupported depth scale: {}.\nUsing default (mbsf) instead.'.format(
            depth_scale))
        depth_scale = 'core_depth'
        ylab = "Depth (mbsf)"
    # fix depth scale for data model 2 if needed
    if data_model_num == 2 and not depth_scale.startswith('sample_'):
        if depth_scale != "age":
            depth_scale = "sample_" + depth_scale
    # collect the data for plotting declination
    Depths, Decs, Incs, Ints = [], [], [], []
    SDepths, SDecs, SIncs, SInts = [], [], [], []
    SSucs = []
    samples = []
    methods, steps, m2 = [], [], []

    if os.path.isfile(meas_file):  # plot the bulk measurement data
        if data_model_num == 3:
            Meas = []
            if 'measurements' in con.tables:
                Meas = con.tables['measurements'].convert_to_pmag_data_list()
            # has measurement_magn_mass ....
            dec_key, inc_key = 'dir_dec', 'dir_inc'
            meth_key, temp_key, ac_key, dc_key = 'method_codes', 'treat_temp', 'treat_ac_field', 'treat_dc_field'
            intlist = ['magnitude', 'magn_moment',
                       'magn_volume', 'magn_mass']
            meas_key = "magn_moment"
        elif data_model_num == 2:
            intlist = ['measurement_magnitude', 'measurement_magn_moment',
                       'measurement_magn_volume', 'measurement_magn_mass']
            temp_key, ac_key, dc_key = 'treatment_temp', 'treatment_ac_field', 'treatment_dc_field'
            dec_key, inc_key = 'measurement_dec', 'measurement_inc'
            Meas, file_type = pmag.magic_read(meas_file)
            meas_key = 'measurement_magn_moment'
        #
        print(len(Meas), ' measurements read in from ', meas_file)
        #
        for m in intlist:  # find the intensity key with data
            # get all non-blank data for this specimen
            meas_data = pmag.get_dictitem(Meas, m, '', 'F')
            if len(meas_data) > 0:
                print('using intensity key:', m)
                meas_key = m
                break
        # fish out the desired method code
        m1 = pmag.get_dictitem(Meas, meth_col_name, method, 'has')
        if method == 'LT-T-Z':
            m2 = pmag.get_dictitem(m1, temp_key, str(
                step), 'eval')  # fish out the desired step
        elif 'LT-AF' in method:
            m2 = pmag.get_dictitem(m1, ac_key, str(step), 'eval')
        elif 'LT-IRM' in method:
            m2 = pmag.get_dictitem(m1, dc_key, str(step), 'eval')
        elif 'LP-X' in method:
            m2 = pmag.get_dictitem(m1, suc_key, '', 'F')
        if len(m2) > 0:
            for rec in m2:  # fish out depths and weights
                D = pmag.get_dictitem(
                    Samps, samp_col_name, rec[samp_col_name], 'T')
                if not D:  # if using an age_file, you may need to sort by site
                    D = pmag.get_dictitem(
                        Samps, site_col_name, rec[site_col_name], 'T')
                depth = pmag.get_dictitem(D, depth_scale, '', 'F')
                if len(depth) > 0:
                    if ylab == 'Age':
                        # get units of ages - assume they are all the same!
                        ylab = ylab + ' (' + depth[0]['age_unit'] + ')'

                    rec[depth_scale] = float(depth[0][depth_scale])
                    rec[meth_col_name] = rec[meth_col_name] + \
                        ':' + depth[0][meth_col_name]
                    if norm:
                        specrecs = pmag.get_dictitem(
                            ErSpecs, spec_col_name, rec[spec_col_name], 'T')
                        specwts = pmag.get_dictitem(
                            specrecs, spec_weight_col_name, "", 'F')
                        if len(specwts) > 0:
                            rec[weight_col_name] = specwts[0][spec_weight_col_name]
                            # fish out data with core_depth and (if needed)
                            # weights
                            Data.append(rec)
                    else:
                        # fish out data with core_depth and (if needed) weights
                        Data.append(rec)
                    if title == "":
                        pieces = rec[samp_col_name].split('-')
                        location = rec.get(loc_col_name, '')
                        title = location

        SData = pmag.sort_diclist(Data, depth_scale)
        for rec in SData:  # fish out bulk measurement data from desired depths
            if dmax == -1 or float(rec[depth_scale]) < dmax and float(rec[depth_scale]) > dmin:
                Depths.append((rec[depth_scale]))
                if method == "LP-X":
                    SSucs.append(float(rec[suc_key]))
                else:
                    if pltDec:
                        Decs.append(float(rec[dec_key]))
                    if pltInc:
                        Incs.append(float(rec[inc_key]))
                    if not norm and pltMag:
                        Ints.append(float(rec[meas_key]))
                    if norm and pltMag:
                        Ints.append(
                            float(rec[meas_key]) / float(rec[spec_weight_col_name]))
            if len(SSucs) > 0:
                maxSuc = max(SSucs)
                minSuc = min(SSucs)
            if len(Ints) > 1:
                maxInt = max(Ints)
                minInt = min(Ints)
        if len(Depths) == 0:
            print('no bulk measurement data matched your request')
        else:
            print(len(Depths), "depths found")
    SpecDepths, SpecDecs, SpecIncs = [], [], []
    FDepths, FDecs, FIncs = [], [], []
    if spc_file:  # add depths to spec data
        # get all the discrete data with best fit lines
        BFLs = pmag.get_dictitem(Specs, meth_col_name, 'DE-BFL', 'has')
        for spec in BFLs:
            if location == "":
                location = spec.get(loc_col_name, "")
            samp = pmag.get_dictitem(
                Samps, samp_col_name, spec[samp_col_name], 'T')
            if len(samp) > 0 and depth_scale in list(samp[0].keys()) and samp[0][depth_scale] != "":
                if ylab == 'Age':
                    # get units of ages - assume they are all the same!
                    ylab = ylab + ' (' + samp[0]['age_unit'] + ')'
                # filter for depth
                if dmax == -1 or float(samp[0][depth_scale]) < dmax and float(samp[0][depth_scale]) > dmin:
                    # fish out data with core_depth
                    SpecDepths.append(float(samp[0][depth_scale]))
                    # fish out data with core_depth
                    SpecDecs.append(float(spec[spec_dec_col_name]))
                    # fish out data with core_depth
                    SpecIncs.append(float(spec[spec_inc_col_name]))
            else:
                print('no core_depth found for: ', spec[spec_col_name])
        # get all the discrete data with best fit lines
        FMs = pmag.get_dictitem(Specs, meth_col_name, 'DE-FM', 'has')
        for spec in FMs:
            if location == "":
                location = spec.get(loc_col_name, "")
            samp = pmag.get_dictitem(
                Samps, samp_col_name, spec[samp_col_name], 'T')
            if len(samp) > 0 and depth_scale in list(samp[0].keys()) and samp[0][depth_scale] != "":
                if ylab == 'Age':
                    # get units of ages - assume they are all the same!
                    ylab = ylab + ' (' + samp[0]['age_unit'] + ')'
                # filter for depth
                if dmax == -1 or float(samp[0][depth_scale]) < dmax and float(samp[0][depth_scale]) > dmin:
                    # fish out data with core_depth
                    FDepths.append(float(samp[0][depth_scale]))
                    # fish out data with core_depth
                    FDecs.append(float(spec[spec_dec_col]))
                    # fish out data with core_depth
                    FIncs.append(float(spec[spec_inc_col]))
            else:
                print('no core_depth found for: ', spec[spec_col_name])
    ResDepths, ResDecs, ResIncs = [], [], []
    if 'age' in depth_scale:  # set y-key
        res_scale = age_col_name
    else:
        res_scale = height_col_name
    if res_file:  # creates lists of Result Data
        for res in Results:
            meths = res[meth_col_name].split(":")
            if 'DE-FM' in meths:
                # filter for depth
                if dmax == -1 or float(res[res_scale]) < dmax and float(res[res_scale]) > dmin:
                    # fish out data with core_depth
                    ResDepths.append(float(res[res_scale]))
                    # fish out data with core_depth
                    ResDecs.append(float(res['average_dec']))
                    # fish out data with core_depth
                    ResIncs.append(float(res['average_inc']))
                    Susc, Sus_depths = [], []
    if dmin == -1:
        if len(Depths) > 0:
            dmin, dmax = Depths[0], Depths[-1]
        if len(FDepths) > 0:
            dmin, dmax = FDepths[0], FDepths[-1]
        if pltSus and len(SDepths) > 0:
            if SDepths[0] < dmin:
                dmin = SDepths[0]
            if SDepths[-1] > dmax:
                dmax = SDepths[-1]
        if len(SpecDepths) > 0:
            if min(SpecDepths) < dmin:
                dmin = min(SpecDepths)
            if max(SpecDepths) > dmax:
                dmax = max(SpecDepths)
        if len(ResDepths) > 0:
            if min(ResDepths) < dmin:
                dmin = min(ResDepths)
            if max(ResDepths) > dmax:
                dmax = max(ResDepths)
    # wig_file and suc_file not currently supported options
    # if suc_file:
    #    with open(suc_file, 'r') as s_file:
    #        sucdat = s_file.readlines()
    #    keys = sucdat[0].replace('\n', '').split(',')  # splits on underscores
    #    for line in sucdat[1:]:
    #        SucRec = {}
    #        for k in range(len(keys)):
    #            SucRec[keys[k]] = line.split(',')[k]
    #        if float(SucRec['Top Depth (m)']) < dmax and float(SucRec['Top Depth (m)']) > dmin and SucRec['Magnetic Susceptibility (80 mm)'] != "":
    #            Susc.append(float(SucRec['Magnetic Susceptibility (80 mm)']))
    #            if Susc[-1] > maxSuc:
    #                maxSuc = Susc[-1]
    #            if Susc[-1] < minSuc:
    #                minSuc = Susc[-1]
    #            Sus_depths.append(float(SucRec['Top Depth (m)']))
    #WIG, WIG_depths = [], []
    # if wig_file:
    #    wigdat, file_type = pmag.magic_read(wig_file)
    #    swigdat = pmag.sort_diclist(wigdat, depth_scale)
    #    keys = list(wigdat[0].keys())
    #    for key in keys:
    #        if key != depth_scale:
    #            plt_key = key
    #            break
    #    for wig in swigdat:
    #        if float(wig[depth_scale]) < dmax and float(wig[depth_scale]) > dmin:
    #            WIG.append(float(wig[plt_key]))
    #            WIG_depths.append(float(wig[depth_scale]))
    tint = 4.5
    plot = 1
    #print('Decs', len(Decs))
    #print('Depths', len(Depths), 'SpecDecs', len(SpecDecs))
    #print('SpecDepths', len(SpecDepths), 'ResDecs', len(ResDecs))
    #print('ResDepths', len(ResDepths), 'SDecs', len(SDecs))
    #print('SDepths', len(SDepths), 'SIincs', len(SIncs))
    #print('Incs', len(Incs))
    if (Decs and Depths) or (SpecDecs and SpecDepths) or (ResDecs and ResDepths) or (SDecs and SDepths) or (SInts and SDepths) or (SIncs and SDepths) or (Incs and Depths):
        main_plot = plt.figure(1, figsize=(width, 8))  # this works
        # pylab.figure(1,figsize=(width,8))
        version_num = pmag.get_version()
        plt.figtext(.02, .01, version_num)
        if pltDec:
            ax = plt.subplot(1, pcol, plot)
            if pltLine:
                plt.plot(Decs, Depths, 'k')
            if len(Decs) > 0:
                plt.plot(Decs, Depths, sym, markersize=size)
            if len(Decs) == 0 and pltLine and len(SDecs) > 0:
                plt.plot(SDecs, SDepths, 'k')
            if len(SDecs) > 0:
                plt.plot(SDecs, SDepths, Ssym, markersize=Ssize)
            if spc_file:
                plt.plot(SpecDecs, SpecDepths, spc_sym, markersize=spc_size)
            if spc_file and len(FDepths) > 0:
                plt.scatter(
                    FDecs, FDepths, marker=spc_sym[-1], edgecolor=spc_sym[0], facecolor='white', s=spc_size**2)
            if res_file:
                plt.plot(ResDecs, ResDepths, res_sym, markersize=res_size)
            if sum_file:
                for core in Cores:
                    depth = float(core[core_depth_key])
                    if depth > dmin and depth < dmax:
                        plt.plot([0, 360.], [depth, depth], 'b--')
                        if pel == plt:
                            plt.text(360, depth + tint, core[core_label_key])
            if pel == plot:
                plt.axis([0, 400, dmax, dmin])
            else:
                plt.axis([0, 360., dmax, dmin])
            plt.xlabel('Declination')
            plt.ylabel(ylab)
            plot += 1
            pmagplotlib.delticks(ax)  # dec xticks are too crowded otherwise
    else:
        print('no data!')
        return False, 'No data found to plot\nTry again with different parameters'
    if pltInc:
        plt.subplot(1, pcol, plot)
        if pltLine:
            plt.plot(Incs, Depths, 'k')
        if len(Incs) > 0:
            plt.plot(Incs, Depths, sym, markersize=size)
        if len(Incs) == 0 and pltLine and len(SIncs) > 0:
            plt.plot(SIncs, SDepths, 'k')
        if len(SIncs) > 0:
            plt.plot(SIncs, SDepths, Ssym, markersize=Ssize)
        if spc_file and len(SpecDepths) > 0:
            plt.plot(SpecIncs, SpecDepths, spc_sym, markersize=spc_size)
        if spc_file and len(FDepths) > 0:
            plt.scatter(
                FIncs, FDepths, marker=spc_sym[-1], edgecolor=spc_sym[0], facecolor='white', s=spc_size**2)
        if res_file:
            plt.plot(ResIncs, ResDepths, res_sym, markersize=res_size)
        if sum_file:
            for core in Cores:
                depth = float(core[core_depth_key])
                if depth > dmin and depth < dmax:
                    if pel == plot:
                        plt.text(90, depth + tint, core[core_label_key])
                    plt.plot([-90, 90], [depth, depth], 'b--')
        plt.plot([0, 0], [dmax, dmin], 'k-')
        if pel == plot:
            plt.axis([-90, 110, dmax, dmin])
        else:
            plt.axis([-90, 90, dmax, dmin])
        plt.xlabel('Inclination')
        plt.ylabel('')
        plot += 1
    if pltMag and len(Ints) > 0 or len(SInts) > 0:
        plt.subplot(1, pcol, plot)
        for pow in range(-10, 10):
            if maxInt * 10**pow > 1:
                break
        if not logit:
            for k in range(len(Ints)):
                Ints[k] = Ints[k] * 10**pow
            for k in range(len(SInts)):
                SInts[k] = SInts[k] * 10**pow
            if pltLine and len(Ints) > 0:
                plt.plot(Ints, Depths, 'k')
            if len(Ints) > 0:
                plt.plot(Ints, Depths, sym, markersize=size)
            if len(Ints) == 0 and pltLine and len(SInts) > 0:
                plt.plot(SInts, SDepths, 'k-')
            if len(SInts) > 0:
                plt.plot(SInts, SDepths, Ssym, markersize=Ssize)
            if sum_file:
                for core in Cores:
                    depth = float(core[core_depth_key])
                    plt.plot([0, maxInt * 10**pow + .1], [depth, depth], 'b--')
                    if depth > dmin and depth < dmax:
                        plt.text(maxInt * 10**pow - .2 * maxInt * 10 **
                                 pow, depth + tint, core[core_label_key])
            plt.axis([0, maxInt * 10**pow + .1, dmax, dmin])
            if not norm:
                plt.xlabel('%s %i %s' % ('Intensity (10^-', pow, ' Am^2)'))
            else:
                plt.xlabel('%s %i %s' % ('Intensity (10^-', pow, ' Am^2/kg)'))
        else:
            if pltLine:
                plt.semilogx(Ints, Depths, 'k')
            if len(Ints) > 0:
                plt.semilogx(Ints, Depths, sym, markersize=size)
            if len(Ints) == 0 and pltLine and len(SInts) > 0:
                plt.semilogx(SInts, SDepths, 'k')
            if len(Ints) == 0 and pltLine == 1 and len(SInts) > 0:
                plt.semilogx(SInts, SDepths, 'k')
            if len(SInts) > 0:
                plt.semilogx(SInts, SDepths, Ssym, markersize=Ssize)
            if sum_file:
                for core in Cores:
                    depth = float(core[core_depth_key])
                    plt.semilogx([minInt, maxInt], [depth, depth], 'b--')
                    if depth > dmin and depth < dmax:
                        plt.text(maxInt - .2 * maxInt, depth +
                                 tint, core[core_label_key])
            minInt = plt.axis()[0]
            plt.axis([minInt, maxInt, dmax, dmin])
            if not norm:
                plt.xlabel('Intensity (Am^2)')
            else:
                plt.xlabel('Intensity (Am^2/kg)')
        plot += 1
    if suc_file or len(SSucs) > 0:
        plt.subplot(1, pcol, plot)
        if len(Susc) > 0:
            if pltLine:
                plt.plot(Susc, Sus_depths, 'k')
            if not logit:
                plt.plot(Susc, Sus_depths, sym, markersize=size)
            if logit:
                plt.semilogx(Susc, Sus_depths, sym, markersize=size)
        if len(SSucs) > 0:
            if not logit:
                plt.plot(SSucs, SDepths, sym, markersize=size)
            if logit:
                plt.semilogx(SSucs, SDepths, sym, markersize=size)
        if sum_file:
            for core in Cores:
                depth = float(core[core_depth_key])
                if not logit:
                    plt.plot([minSuc, maxSuc], [depth, depth], 'b--')
                if logit:
                    plt.semilogx([minSuc, maxSuc], [depth, depth], 'b--')
        plt.axis([minSuc, maxSuc, dmax, dmin])
        plt.xlabel('Susceptibility')
        plot += 1
    # if wig_file:
    #    plt.subplot(1, pcol, plot)
    #    plt.plot(WIG, WIG_depths, 'k')
    #    if sum_file:
    #        for core in Cores:
    #            depth = float(core[core_depth_key])
    #            plt.plot([WIG[0], WIG[-1]], [depth, depth], 'b--')
    #    plt.axis([min(WIG), max(WIG), dmax, dmin])
    #    plt.xlabel(plt_key)
    #    plot += 1
    if pltTime:
        ax1 = plt.subplot(1, pcol, plot)
        ax1.axis([-.25, 1.5, amax, amin])
        plot += 1
        TS, Chrons = pmag.get_ts(timescale)
        X, Y, Y2 = [0, 1], [], []
        cnt = 0
        if amin < TS[1]:  # in the Brunhes
            Y = [amin, amin]  # minimum age
            Y1 = [TS[1], TS[1]]  # age of the B/M boundary
            # color in Brunhes, black
            ax1.fill_between(X, Y, Y1, facecolor='black')
        for d in TS[1:]:
            pol = cnt % 2
            cnt += 1
            if d <= amax and d >= amin:
                ind = TS.index(d)
                Y = [TS[ind], TS[ind]]
                Y1 = [TS[ind + 1], TS[ind + 1]]
                if pol:
                    # fill in every other time
                    ax1.fill_between(X, Y, Y1, facecolor='black')
        ax1.plot([0, 1, 1, 0, 0], [amin, amin, amax, amax, amin], 'k-')
        ax2 = ax1.twinx()
        plt.ylabel("Age (Ma): " + timescale)
        for k in range(len(Chrons) - 1):
            c = Chrons[k]
            cnext = Chrons[k + 1]
            d = cnext[1] - old_div((cnext[1] - c[1]), 3.)
            if d >= amin and d < amax:
                # make the Chron boundary tick
                ax2.plot([1, 1.5], [c[1], c[1]], 'k-')
                ax2.text(1.05, d, c[0])
        ax2.axis([-.25, 1.5, amax, amin])
    figname = location + '_m:_' + method + '_core-depthplot.' + fmt
    plt.title(location)
    return main_plot, figname

Response: Function to plot a core depth of a single species and sample file.


Instruction:
Make a summary of the following Python 3 code
def download_magic(infile, dir_path='.', input_dir_path='',
                   overwrite=False, print_progress=True,
                   data_model=3., separate_locs=False):
    """
    takes the name of a text file downloaded from the MagIC database and
    unpacks it into magic-formatted files. by default, download_magic assumes
    that you are doing everything in your current directory. if not, you may
    provide optional arguments dir_path (where you want the results to go) and
    input_dir_path (where the downloaded file is IF that location is different from
    dir_path).

    Parameters
    ----------
    infile : str
        MagIC-format file to unpack
    dir_path : str
        output directory (default ".")
    input_dir_path : str, default ""
        path for intput file if different from output_dir_path (default is same)
    overwrite: bool
        overwrite current directory (default False)
    print_progress: bool
        verbose output (default True)
    data_model : float
        MagIC data model 2.5 or 3 (default 3)
    separate_locs : bool
        create a separate directory for each location (Location_*)
        (default False)
    """
    if data_model == 2.5:
        method_col = "magic_method_codes"
    else:
        method_col = "method_codes"

    input_dir_path, dir_path = pmag.fix_directories(input_dir_path, dir_path)
    infile = pmag.resolve_file_name(infile, input_dir_path)
    # try to deal reasonably with unicode errors
    try:
        f = codecs.open(infile, 'r', "utf-8")
        infile = f.readlines()
    except UnicodeDecodeError:
        f = codecs.open(infile, 'r', "Latin-1")
        infile = f.readlines()
    f.close()
    File = []  # will contain all non-blank lines from downloaded file
    for line in infile:
        line = line.replace('\n', '')
        if line[0:4] == '>>>>' or len(line.strip()) > 0:  # skip blank lines
            File.append(line)
    LN = 0  # tracks our progress iterating through File
    type_list = []
    filenum = 0
    while LN < len(File) - 1:
        line = File[LN]
        if ">>>>" in line:
            LN += 1
            continue
        file_type = line.split('\t')[1]
        file_type = file_type.lower()
        if file_type[-1] == "\n":
            file_type = file_type[:-1]
        if print_progress == True:
            print('working on: ', repr(file_type))
        if file_type not in type_list:
            type_list.append(file_type)
        else:
            filenum += 1
        LN += 1
        line = File[LN]
        # skip empty tables
        if line == ">>>>>>>>>>":
            LN += 1
            continue
        keys = line.replace('\n', '').split('\t')
        if keys[0][0] == '.':
            keys = line.replace('\n', '').replace('.', '').split('\t')
            keys.append('RecNo')  # cludge for new MagIC download format
        LN += 1
        Recs = []
        while LN < len(File):
            line = File[LN]
            # finish up one file type and then break
            if ">>>>" in line and len(Recs) > 0:
                if filenum == 0:
                    outfile = os.path.join(dir_path, file_type.strip() + '.txt')
                else:
                    outfile = os.path.join(dir_path, file_type.strip() + '_' + str(filenum) + '.txt')
                NewRecs = []
                for rec in Recs:
                    if method_col in list(rec.keys()):
                        meths = rec[method_col].split(":")
                        if len(meths) > 0:
                            methods = ""
                            for meth in meths:
                                methods = methods + meth.strip() + ":"  # get rid of nasty spaces!!!!!!
                            rec[method_col] = methods[:-1]
                    NewRecs.append(rec)
                pmag.magic_write(outfile, Recs, file_type)
                if print_progress == True:
                    print(file_type, " data put in ", outfile)
                Recs = []
                LN += 1
                break
            # keep adding records of the same file type
            else:
                rec = line.split('\t')
                Rec = {}
                if len(rec) == len(keys):
                    for k in range(len(rec)):
                        Rec[keys[k]] = rec[k]
                    Recs.append(Rec)
                # in case of magic_search_results.txt, which has an extra
                # column:
                elif len(rec) - len(keys) == 1:
                    for k in range(len(rec))[:-1]:
                        Rec[keys[k]] = rec[k]
                    Recs.append(Rec)
                elif len(rec) < len(keys):
                    for k in range(len(rec)):
                        Rec[keys[k]] = rec[k]
                    for k in range(len(rec), len(keys)):
                        Rec[keys[k]] = ""
                    Recs.append(Rec)
                else:
                    print('WARNING:  problem in file with line: ')
                    print(line)
                    print('skipping....')
                LN += 1
    if len(Recs) > 0:
        if filenum == 0:
            outfile = os.path.join(dir_path, file_type.strip() + '.txt')
        else:
            outfile = os.path.join(dir_path, file_type.strip() + '_' + str(filenum) + '.txt')
        NewRecs = []
        for rec in Recs:
            if method_col in list(rec.keys()):
                meths = rec[method_col].split(":")
                if len(meths) > 0:
                    methods = ""
                    for meth in meths:
                        methods = methods + meth.strip() + ":"  # get rid of nasty spaces!!!!!!
                    rec[method_col] = methods[:-1]
            NewRecs.append(rec)
        pmag.magic_write(outfile, Recs, file_type)
        if print_progress == True:
            print(file_type, " data put in ", outfile)
    # look through locations table and create separate directories for each
    # location
    if separate_locs:
        con = cb.Contribution(dir_path)
        con.propagate_location_to_measurements()
        con.propagate_name_down('location', 'samples')
        for dtype in con.tables:
            con.write_table_to_file(dtype)
        locs, locnum = [], 1
        if 'locations' in type_list:
            locs, file_type = pmag.magic_read(
                os.path.join(dir_path, 'locations.txt'))
        if len(locs) > 0:  # at least one location
            # go through unique location names
            for loc_name in set([loc.get('location') for loc in locs]):
                if print_progress == True:
                    print('location_' + str(locnum) + ": ", loc_name)
                lpath = os.path.join(dir_path, 'Location_' + str(locnum))
                locnum += 1
                try:
                    os.mkdir(lpath)
                except:
                    print('directory ', lpath,
                          ' already exists - overwriting everything: {}'.format(overwrite))
                    if not overwrite:
                        print("-W- download_magic encountered a duplicate subdirectory ({}) and could not finish.\nRerun with overwrite=True, or unpack this file in a different directory.".format(lpath))
                        return False
                for f in type_list:
                    fname = os.path.join(dir_path, f + '.txt')
                    if print_progress == True:
                        print('unpacking: ', fname)
                    recs, file_type = pmag.magic_read(fname)
                    if print_progress == True:
                        print(len(recs), ' read in')
                    lrecs = pmag.get_dictitem(recs, 'location', loc_name, 'T')
                    if len(lrecs) > 0:
                        outfile_name = os.path.join(lpath, f + ".txt")
                        pmag.magic_write(outfile_name, lrecs, file_type)
                        if print_progress == True:
                            print(len(lrecs), ' stored in ', outfile_name)
    return True

Response: Download a magic file into a new directory.


Instruction:
Here you have a function in Python 3, explain what it does
def upload_magic2(concat=0, dir_path='.', data_model=None):
    SpecDone = []
    locations = []
    concat = int(concat)
    files_list = ["er_expeditions.txt", "er_locations.txt", "er_samples.txt", "er_specimens.txt", "er_sites.txt", "er_ages.txt", "er_citations.txt", "er_mailinglist.txt", "magic_measurements.txt",
                  "rmag_hysteresis.txt", "rmag_anisotropy.txt", "rmag_remanence.txt", "rmag_results.txt", "pmag_specimens.txt", "pmag_samples.txt", "pmag_sites.txt", "pmag_results.txt", "pmag_criteria.txt", "magic_instruments.txt"]
    file_names = [os.path.join(dir_path, f) for f in files_list]

    # begin the upload process
    up = os.path.join(dir_path, "upload.txt")
    if os.path.exists(up):
        os.remove(up)
    RmKeys = ['citation_label', 'compilation', 'calculation_type', 'average_n_lines', 'average_n_planes',
              'specimen_grade', 'site_vgp_lat', 'site_vgp_lon', 'direction_type', 'specimen_Z',
              'magic_instrument_codes', 'cooling_rate_corr', 'cooling_rate_mcd', 'anisotropy_atrm_alt',
              'anisotropy_apar_perc', 'anisotropy_F', 'anisotropy_F_crit', 'specimen_scat',
              'specimen_gmax', 'specimen_frac', 'site_vadm', 'site_lon', 'site_vdm', 'site_lat',
              'measurement_chi', 'specimen_k_prime', 'specimen_k_prime_sse', 'external_database_names',
              'external_database_ids', 'Further Notes', 'Typology', 'Notes (Year/Area/Locus/Level)',
              'Site', 'Object Number', 'dir_n_specimens']
    print("-I- Removing: ", RmKeys)
    CheckDec = ['_dec', '_lon', '_azimuth', 'dip_direction']
    CheckSign = ['specimen_b_beta']
    last = file_names[-1]
    methods, first_file = [], 1
    for File in file_names:
        # read in the data
        Data, file_type = pmag.magic_read(File)
        if (file_type != "bad_file") and (file_type != "empty_file"):
            print("-I- file", File, " successfully read in")
            if len(RmKeys) > 0:
                for rec in Data:
                    # remove unwanted keys
                    for key in RmKeys:
                        if key == 'specimen_Z' and key in list(rec.keys()):
                            # change  # change this to lower case
                            rec[key] = 'specimen_z'
                        if key in list(rec.keys()):
                            del rec[key]  # get rid of unwanted keys
                    # make sure b_beta is positive
                    # ignore blanks
                    if 'specimen_b_beta' in list(rec.keys()) and rec['specimen_b_beta'] != "":
                        if float(rec['specimen_b_beta']) < 0:
                            # make sure value is positive
                            rec['specimen_b_beta'] = str(
                                -float(rec['specimen_b_beta']))
                            print('-I- adjusted to positive: ',
                                  'specimen_b_beta', rec['specimen_b_beta'])
                    # make all declinations/azimuths/longitudes in range
                    # 0=>360.
                    rec = pmag.adjust_all_to_360(rec)
            if file_type == 'er_locations':
                for rec in Data:
                    locations.append(rec['er_location_name'])
            if file_type in ['pmag_samples', 'pmag_sites', 'pmag_specimens']:
                # if there is NO pmag data for specimens (samples/sites),
                # do not try to write it to file
                # (this causes validation errors, elsewise)
                ignore = True
                for rec in Data:
                    if ignore == False:
                        break
                    keys = list(rec.keys())
                    exclude_keys = ['er_citation_names', 'er_site_name', 'er_sample_name',
                                    'er_location_name', 'er_specimen_names', 'er_sample_names']
                    for key in exclude_keys:
                        if key in keys:
                            keys.remove(key)
                    for key in keys:
                        if rec[key]:
                            ignore = False
                            break
                if ignore:
                    continue

            if file_type == 'er_samples':  # check to only upload top priority orientation record!
                NewSamps, Done = [], []
                for rec in Data:
                    if rec['er_sample_name'] not in Done:
                        orient, az_type = pmag.get_orient(
                            Data, rec['er_sample_name'])
                        NewSamps.append(orient)
                        Done.append(rec['er_sample_name'])
                Data = NewSamps
                print(
                    'only highest priority orientation record from er_samples.txt read in ')
            if file_type == 'er_specimens':  # only specimens that have sample names
                NewData, SpecDone = [], []
                for rec in Data:
                    if rec['er_sample_name'] in Done:
                        NewData.append(rec)
                        SpecDone.append(rec['er_specimen_name'])
                    else:
                        print('no valid sample record found for: ')
                        print(rec)
                Data = NewData
                # print 'only measurements that have specimen/sample info'
            if file_type == 'magic_measurements':  # only measurements that have specimen names
                no_specs = []
                NewData = []
                for rec in Data:
                    if rec['er_specimen_name'] in SpecDone:
                        NewData.append(rec)
                    else:
                        print('no valid specimen record found for: ')
                        print(rec)
                        no_specs.append(rec)
                # print set([record['er_specimen_name'] for record in
                # no_specs])
                Data = NewData
    # write out the data
            if len(Data) > 0:
                if first_file == 1:
                    keystring = pmag.first_rec(up, Data[0], file_type)
                    first_file = 0
                else:
                    keystring = pmag.first_up(up, Data[0], file_type)
                for rec in Data:
                    # collect the method codes
                    if "magic_method_codes" in list(rec.keys()):
                        meths = rec["magic_method_codes"].split(':')
                        for meth in meths:
                            if meth.strip() not in methods:
                                if meth.strip() != "LP-DIR-":
                                    methods.append(meth.strip())
                    try:
                        pmag.putout(up, keystring, rec)
                    except IOError:
                        print('-W- File input error: slowing down')
                        time.sleep(1)
                        pmag.putout(up, keystring, rec)

    # write out the file separator
            f = open(up, 'a')
            f.write('>>>>>>>>>>\n')
            f.close()
            print(file_type, 'written to ', up)
        else:
            print('File:', File)
            print(file_type, 'is bad or non-existent - skipping ')

    # write out the methods table
    first_rec, MethRec = 1, {}
    for meth in methods:
        MethRec["magic_method_code"] = meth
        if first_rec == 1:
            meth_keys = pmag.first_up(up, MethRec, "magic_methods")
        first_rec = 0
        try:
            pmag.putout(up, meth_keys, MethRec)
        except IOError:
            print('-W- File input error: slowing down')
            time.sleep(1)
            pmag.putout(up, meth_keys, MethRec)
    if concat == 1:
        f = open(up, 'a')
        f.write('>>>>>>>>>>\n')
        f.close()

    if os.path.isfile(up):
        from . import validate_upload2 as validate_upload
        validated = False
        validated, errors = validate_upload.read_upload(up, data_model)

    else:
        print("no data found, upload file not created")
        return False, "no data found, upload file not created", None

    # rename upload.txt according to location + timestamp
    format_string = "%d.%b.%Y"
    if locations:
        location = locations[0].replace(' ', '_')
        new_up = location + '_' + time.strftime(format_string) + '.txt'
    else:
        new_up = 'unknown_location_' + time.strftime(format_string) + '.txt'

    new_up = os.path.join(dir_path, new_up)
    if os.path.isfile(new_up):
        fname, extension = os.path.splitext(new_up)
        for i in range(1, 100):
            if os.path.isfile(fname + "_" + str(i) + extension):
                continue
            else:
                new_up = fname + "_" + str(i) + extension
                break
    os.rename(up, new_up)
    print("Finished preparing upload file: {} ".format(new_up))
    if not validated:
        print("-W- validation of upload file has failed.\nYou can still upload {} to MagIC,\nbut you will need to fix the above errors before your contribution can be activated.".format(new_up))
        return False, "Validation of your upload file has failed.\nYou can still upload {} to MagIC,\nbut you will need to fix the above errors before your contribution can be activated.".format(new_up), errors
    return new_up, '', None

Response: Uploads a magic file to MagIC database.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def upload_magic(concat=False, dir_path='.', dmodel=None, vocab="", contribution=None,
                 input_dir_path=""):
    """
    Finds all magic files in a given directory, and compiles them into an
    upload.txt file which can be uploaded into the MagIC database.
    Parameters
    ----------
    concat : boolean where True means do concatenate to upload.txt file in dir_path,
        False means write a new file (default is False)
    dir_path : string for input/output directory (default ".")
    dmodel : pmagpy data_model.DataModel object,
        if not provided will be created (default None)
    vocab : pmagpy controlled_vocabularies3.Vocabulary object,
        if not provided will be created (default None)
    contribution : pmagpy contribution_builder.Contribution object, if not provided will be created
        in directory (default None)
    input_dir_path : str, default ""
        path for intput files if different from output dir_path (default is same)

    Returns
    ----------
    tuple of either: (False, error_message, errors, all_failing_items)
    if there was a problem creating/validating the upload file
    or: (filename, '', None, None) if the file creation was fully successful.
    """
    input_dir_path, dir_path = pmag.fix_directories(input_dir_path, dir_path)
    locations = []
    concat = int(concat)
    dtypes = ["locations", "samples", "specimens", "sites", "ages", "measurements",
              "criteria", "contribution", "images"]
    fnames = [os.path.join(input_dir_path, dtype + ".txt") for dtype in dtypes]
    file_names = [fname for fname in fnames if os.path.exists(fname)]
    error_fnames = [dtype + "_errors.txt" for dtype in dtypes]
    error_full_fnames = [os.path.join(
        dir_path, fname) for fname in error_fnames if os.path.exists(os.path.join(dir_path, fname))]
    print('-I- Removing old error files from {}: {}'.format(dir_path,
                                                            ", ".join(error_fnames)))
    for error in error_full_fnames:
        os.remove(error)
    if isinstance(contribution, cb.Contribution):
        # if contribution object provided, use it
        con = contribution
        for table_name in con.tables:
            con.tables[table_name].write_magic_file()
    elif file_names:
        # otherwise create a new Contribution in dir_path
        con = Contribution(input_dir_path, vocabulary=vocab)
    else:
        # if no contribution is provided and no contribution could be created,
        # you are out of luck
        print("-W- No 3.0 files found in your directory: {}, upload file not created".format(input_dir_path))
        return False, "no 3.0 files found, upload file not created", None, None

    # if the contribution has no tables, you can't make an upload file
    if not con.tables.keys():
        print("-W- No tables found in your contribution in directory {}, file not created".format(input_dir_path))
        return False, "-W- No tables found in your contribution, file not created", None, None

    con.propagate_cols(['core_depth', 'composite_depth'],
                       'sites', 'samples', down=False)

    # take out any extra added columns
    # con.remove_non_magic_cols()

    # begin the upload process
    up = os.path.join(dir_path, "upload.txt")
    if os.path.exists(up):
        os.remove(up)
    RmKeys = ('citation_label', 'compilation', 'calculation_type', 'average_n_lines', 'average_n_planes',
              'specimen_grade', 'site_vgp_lat', 'site_vgp_lon', 'direction_type', 'specimen_Z',
              'magic_instrument_codes', 'cooling_rate_corr', 'cooling_rate_mcd', 'anisotropy_atrm_alt',
              'anisotropy_apar_perc', 'anisotropy_F', 'anisotropy_F_crit', 'specimen_scat',
              'specimen_gmax', 'specimen_frac', 'site_vadm', 'site_lon', 'site_vdm', 'site_lat',
              'measurement_chi', 'specimen_k_prime', 'specimen_k_prime_sse', 'external_database_names',
              'external_database_ids', 'Further Notes', 'Typology', 'Notes (Year/Area/Locus/Level)',
              'Site', 'Object Number', 'version', 'site_definition')
    #print("-I- Removing: ", RmKeys)
    extra_RmKeys = {'measurements': ['sample', 'site', 'location'],
                    'specimens': ['site', 'location', 'age', 'age_unit', 'age_high',
                                  'age_low', 'age_sigma', 'specimen_core_depth'],
                    'samples': ['location', 'age', 'age_unit', 'age_high', 'age_low',
                                'age_sigma', 'core_depth', 'composite_depth'],
                    'sites': ['texture', 'azimuth', 'azimuth_dec_correction', 'dip',
                              'orientation_quality', 'sample_alternatives', 'timestamp'],
                    'ages': ['level']}

    failing = []
    all_failing_items = {}
    if not dmodel:
        dmodel = data_model.DataModel()
    last_file_type = sorted(con.tables.keys())[-1]
    for file_type in sorted(con.tables.keys()):
        container = con.tables[file_type]
        # format all float values to have correct number of decimals
        container.all_to_str()
        # make sure all nans and Nones are changed to ''
        container.df.fillna('')
        df = container.df
        if len(df):
            print("-I- {} file successfully read in".format(file_type))
    # make some adjustments to clean up data
            # drop non MagIC keys
            DropKeys = list(RmKeys) + extra_RmKeys.get(file_type, [])
            DropKeys = set(DropKeys).intersection(df.columns)
            if DropKeys:
                print(
                    '-I- dropping these columns: {} from the {} table'.format(', '.join(DropKeys), file_type))
                df.drop(DropKeys, axis=1, inplace=True)
            container.df = df
            unrecognized_cols = container.get_non_magic_cols()
            if unrecognized_cols:
                print('-W- {} table still has some unrecognized columns: {}'.format(file_type.title(),
                                                                                ", ".join(unrecognized_cols)))
            # make sure int_b_beta is positive
            if 'int_b_beta' in df.columns:
                # get rid of empty strings
                df = df.replace(r'\s+( +\.)|#', np.nan,
                                regex=True).replace('', np.nan)
                try:
                    df['int_b_beta'] = df['int_b_beta'].astype(
                        float).apply(abs)
                except ValueError:
                    "-W- Non numeric values found in int_b_beta column.\n   Could not apply absolute value."
            # make all declinations/azimuths/longitudes in range 0=>360.
            relevant_cols = val_up3.get_degree_cols(df)
            for col in relevant_cols:
                df[col] = df[col].apply(pmag.adjust_val_to_360)
            # get list of location names
            if file_type == 'locations':
                locations = sorted(df['location'].unique())
            # LJ: need to deal with this
            # use only highest priority orientation -- not sure how this works
            elif file_type == 'samples':
                # orient,az_type=pmag.get_orient(Data,rec['sample'])
                pass
            # include only specimen records with samples
            elif file_type == 'specimens':
                df = df[df['sample'].notnull()]
                if 'samples' in con.tables:
                    samp_df = con.tables['samples'].df
                    df = df[df['sample'].isin(samp_df.index.unique())]
            # include only measurements with specmiens
            elif file_type == 'measurements':
                df = df[df['specimen'].notnull()]
                if 'specimens' in con.tables:
                    spec_df = con.tables['specimens'].df
                    df = df[df['specimen'].isin(spec_df.index.unique())]
    # run validations
            res = val_up3.validate_table(
                con, file_type, output_dir=dir_path)  # , verbose=True)
            if res:
                dtype, bad_rows, bad_cols, missing_cols, missing_groups, failing_items = res
                if dtype not in all_failing_items:
                    all_failing_items[dtype] = {}
                all_failing_items[dtype]["rows"] = failing_items
                all_failing_items[dtype]["missing_columns"] = missing_cols
                all_failing_items[dtype]["missing_groups"] = missing_groups
                failing.append(dtype)
    # write out the data
            if len(df):
                container.write_magic_file(up, append=True, multi_type=True)
    # write out the file separator
            if last_file_type != file_type:
                f = open(up, 'a')
                f.write('>>>>>>>>>>\n')
                f.close()
                print("-I-", file_type, 'written to ', up)
            else:  # last file, no newline at end of file
                #f = open(up, 'a')
                # f.write('>>>>>>>>>>')
                # f.close()
                print("-I-", file_type, 'written to ', up)
    # if there was no understandable data
        else:
            print(file_type, 'is bad or non-existent - skipping ')
    # add to existing file
    if concat:
        f = open(up, 'a')
        f.write('>>>>>>>>>>\n')
        f.close()

    if not os.path.isfile(up):
        print("no data found, upload file not created")
        return False, "no data found, upload file not created", None, None

    # rename upload.txt according to location + timestamp
    format_string = "%d.%b.%Y"
    if locations:
        locs = set(locations)
        locs = sorted(locs)[:3]
        #location = locations[0].replace(' ', '_')
        try:
            locs = [loc.replace(' ', '-') for loc in locs]
        except AttributeError:
            locs = ["unknown_location"]
        location = "_".join(locs)
        new_up = location + '_' + time.strftime(format_string) + '.txt'
    else:
        new_up = 'unknown_location_' + time.strftime(format_string) + '.txt'

    new_up = os.path.join(dir_path, new_up)
    if os.path.isfile(new_up):
        fname, extension = os.path.splitext(new_up)
        for i in range(1, 100):
            if os.path.isfile(fname + "_" + str(i) + extension):
                continue
            else:
                new_up = fname + "_" + str(i) + extension
                break
    if not up:
        print("-W- Could not create an upload file")
        return False, "Could not create an upload file", None, None
    os.rename(up, new_up)
    print("Finished preparing upload file: {} ".format(new_up))
    if failing:
        print("-W- These tables have errors: {}".format(", ".join(failing)))
        print("-W- validation of upload file has failed.\nYou can still upload {} to MagIC,\nbut you will need to fix the above errors before your contribution can be activated.".format(new_up))
        return False, "Validation of your upload file has failed.\nYou can still upload {} to MagIC,\nbut you will need to fix the above errors before your contribution can be activated.".format(new_up), failing, all_failing_items
    else:
        print("-I- Your file has passed validation.  You should be able to upload it to the MagIC database without trouble!")
    return new_up, '', None, None

Response: Uploads all files in a given directory and returns a tuple of True and error message and errors for the upload. txt file.