Instruction:
Make a summary of the following Python 3 code
def pop_header(self, hkey, ignore_error=False):

        # try the integer approach first to allow negative values
        if type(hkey) is not str:
            try:
                return self.headers.pop(self.hkeys.pop(hkey))
            except:
                if not ignore_error:
                    print("ERROR: pop_header() could not find hkey "+str(hkey))
                return None
        else:

            try:
                # find the key integer and pop it
                hkey = self.hkeys.index(hkey)

                # pop it!
                return self.headers.pop(self.hkeys.pop(hkey))

            except:
                if not ignore_error:
                    print("ERROR: pop_header() could not find hkey "+str(hkey))
                return

Response: This will remove and return the specified header value from the list of headers.


Instruction:
Here you have a function in Python 3, explain what it does
def rename_column(self, column, new_name):
        if type(column) is not str: column = self.ckeys[column]
        self.ckeys[self.ckeys.index(column)] = new_name
        self.columns[new_name] = self.columns.pop(column)
        return self

Response: This will rename the column.


Instruction:
Can you implement a function in Python 3 that
removes data points not satisfying the supplied conditions. Conditions can be truth arrays (having the same length as the columns!) or scripted strings. Example Workflow ---------------- d1 = spinmob.data.load() d2 = d1.trim( (2<d1[0]) & (d1[0]<10) | (d1[3]==22), 'sin(d[2])*h("gain")<32.2') Note this will not modify the databox, rather it will generate a new one with the same header information and return it.

Response:
def trim(self, *conditions):
        """
        Removes data points not satisfying the supplied conditions. Conditions
        can be truth arrays (having the same length as the columns!)
        or scripted strings.

        Example Workflow
        ----------------
        d1 = spinmob.data.load()
        d2 = d1.trim( (2<d1[0]) & (d1[0]<10) | (d1[3]==22), 'sin(d[2])*h("gain")<32.2')

        Note this will not modify the databox, rather it will generate a new
        one with the same header information and return it.
        """
        conditions = list(conditions)

        # if necessary, evaluate string scripts
        for n in range(len(conditions)):
            if type(conditions[n]) is str:
                conditions[n] = self.execute_script(conditions[n])

        # make a new databox with the same options and headers
        new_databox = databox(delimiter=self.delimiter)
        new_databox.copy_headers(self)

        # trim it up, send it out.
        cs = _s.fun.trim_data_uber(self, conditions)
        for n in range(len(cs)): new_databox.append_column(cs[n], self.ckeys[n])

        return new_databox


Instruction:
Can you tell what is the following Python 3 function doing
def transpose(self):
        # Create an empty databox with the same headers and delimiter.
        d = databox(delimter=self.delimiter)
        self.copy_headers(d)

        # Get the transpose
        z = _n.array(self[:]).transpose()

        # Build the columns of the new databox
        for n in range(len(z)): d['c'+str(n)] = z[n]

        return d

Response: Returns a copy of this databox with the columns as rows.


Instruction:
Can you tell what is the following Python 3 function doing
def update_headers(self, dictionary, keys=None):
        if keys is None: keys = list(dictionary.keys())
        for k in keys: self.insert_header(k, dictionary[k])
        return self

Response: Updates the header with the supplied dictionary.


Instruction:
Make a summary of the following Python 3 code
def c(self, *args, **kwargs):
        # If not arguments, print everything
        if len(args) + len(kwargs) == 0:

            print("Columns")
            if len(self.ckeys)==0: print ('  No columns of data yet.')

            # Loop over the ckeys and display their information
            for n in range(len(self.ckeys)):
                print('  '+str(n)+': '+str(self.ckeys[n])+' '+str(_n.shape(self[n])))
            return

        # Otherwise, find n
        elif len(args):   n = args[0]
        elif len(kwargs):
            for k in kwargs: n = kwargs[k]

        # Nothing to do here.
        if len(self.columns) == 0:   return None

        # if it's a string, use it as a key for the dictionary
        if type(n)   is str: return self.columns[n]

        # if it's a list, return the specified columns
        if type(n) in [list, tuple, range]:
            output = []
            for i in n: output.append(self[i])
            return output

        # If it's a slice, do the slice thing
        if type(n) is slice:
            start = n.start
            stop  = n.stop
            step  = n.step

            # Fix up the unspecifieds
            if start == None: start = 0
            if stop  == None or stop>len(self): stop  = len(self)
            if step  == None: step  = 1

            # Return what was asked for
            return self[range(start, stop, step)]

        # Otherwise assume it's an integer
        return self.columns[self.ckeys[n]]

Response:
Takes a single argument or keyword argument and returns the specified
        column.


Instruction:
Here you have a function in Python 3, explain what it does
def h(self, *args, **kwargs):
        # If not arguments, print everything
        if len(args) + len(kwargs) == 0:
            print("Headers")
            for n in range(len(self.hkeys)):
                print('  '+str(n)+': '+str(self.hkeys[n])+' = '+repr(self.h(n)))
            return

        # first loop over kwargs if there are any to set header elements
        for k in list(kwargs.keys()):
            self.insert_header(k, kwargs[k])

        # Meow search for a key if specified
        if len(args):
            # this can be shortened. Eventually, it'd be nice to get a tuple back!
            hkey = args[0]

            # if this is an index
            if type(hkey) in [int, int]: return self.headers[self.hkeys[hkey]]

            # if this is an exact match
            elif hkey in self.hkeys:      return self.headers[hkey]

            # Look for a fragment.
            else:
                for k in self.hkeys:
                    if k.find(hkey) >= 0:
                        return self.headers[k]
                print()
                print("ERROR: Couldn't find '"+str(hkey) + "' in header.")
                print("Possible values:")
                for k in self.hkeys: print(k)
                print()
                return None

Response: This function searches through the header keys and returns the value of the specified key in the header.


Instruction:
How would you explain what the following Python 3 function does
def set(self, **kwargs):
        if len(kwargs)==0: return self

        # Set settings
        for k in list(kwargs.keys()): self[k] = kwargs[k]

        # Plot if we're supposed to.
        if self['autoplot'] and not self._initializing: self.plot()

        return self

Response: Sets the value of the parameter in the current object.


Instruction:
Explain what the following Python 3 code does
def print_fit_parameters(self):
        s = ''
        if self.results and self.results[1] is not None:
            s = s + "\n# FIT RESULTS (reduced chi squared = {:s})\n".format(str(self.reduced_chi_squareds()))
            for n in range(len(self._pnames)):
                s = s + "{:10s} = {:G}\n".format(self._pnames[n], self.results[0][n])

        elif self.results and self.results[1] is None:
            s = s + "\n# FIT DID NOT CONVERGE\n"
            for n in range(len(self._pnames)):
                s = s + "{:10s} = {:G}\n".format(self._pnames[n], self.results[0][n])

        else: s = s + "\n# NO FIT RESULTS\n"

        print(s)

Response: Print the fit parameters in a way that can be copied into python.


Instruction:
Implement a function in Python 3 to
set the functions used to describe the data.

Response:
def set_functions(self,  f='a*x*cos(b*x)+c', p='a=-0.2, b, c=3', c=None, bg=None, **kwargs):
        """
        Sets the function(s) used to describe the data.

        Parameters
        ----------
        f=['a*x*cos(b*x)+c', 'a*x+c']
            This can be a string function, a defined function
            my_function(x,a,b), or a list of some combination
            of these two types of objects. The length of such
            a list must be equal to the number of data sets
            supplied to the fit routine.
        p='a=1.5, b'
            This must be a comma-separated string list of
            parameters used to fit. If an initial guess value is
            not specified, 1.0 will be used.
            If a function object is supplied, it is assumed that
            this string lists the parameter names in order.
        c=None
            Fit _constants; like p, but won't be allowed to float
            during the fit. This can also be None.
        bg=None
            Can be functions in the same format as f describing a
            background (which can be subtracted during fits, etc)

        Additional keyword arguments are added to the globals used when
        evaluating the functions.
        """

        # initialize everything
        self._pnames    = []
        self._cnames    = []
        self._pguess    = []
        self._constants = []

        # Update the globals
        self._globals.update(kwargs)

        # store these for later
        self._f_raw  = f
        self._bg_raw = bg

        # break up the constant names and initial values.
        if c:
            for s in c.split(','):

                # split by '=' and see if there is an initial value
                s = s.split('=')

                # add the name to the list
                self._cnames.append(s[0].strip())

                # if there is a guess value, add this (or 1.0)
                if len(s) > 1: self._constants.append(float(s[1]))
                else:          self._constants.append(1.0)

        # break up the parameter names and initial values.
        for s in p.split(','):

            # split by '=' and see if there is an initial value
            s = s.split('=')

            # add the name to the list
            self._pnames.append(s[0].strip())

            # if there is a guess value, add this (or 1.0)
            if len(s) > 1: self._pguess.append(float(s[1]))
            else:          self._pguess.append(1.0)

        # use the internal settings we just set to create the functions
        self._update_functions()

        if self['autoplot']: self.plot()

        return self


Instruction:
Given the following Python 3 function, write the documentation
def _update_functions(self):

        self.f             = []
        self.bg            = []
        self._fnames       = []
        self._bgnames      = []
        self._odr_models   = [] # Like f, but different parameters, for use in ODR

        f  = self._f_raw
        bg = self._bg_raw

        # make sure f and bg are lists of matching length
        if not _s.fun.is_iterable(f) : f  = [f]
        if not _s.fun.is_iterable(bg): bg = [bg]
        while len(bg) < len(f): bg.append(None)

        # get a comma-delimited string list of parameter names for the "normal" function
        pstring = 'x, ' + ', '.join(self._pnames)

        # get the comma-delimited string for the ODR function
        pstring_odr = 'x, '
        for n in range(len(self._pnames)): pstring_odr = pstring_odr+'p['+str(n)+'], '

        # update the globals for the functions
        # the way this is done, we must redefine the functions
        # every time we change a constant
        for cname in self._cnames: self._globals[cname] = self[cname]

        # loop over all the functions and create the master list
        for n in range(len(f)):

            # if f[n] is a string, define a function on the fly.
            if isinstance(f[n], str):

                # "Normal" least squares function (y-error bars only)
                self.f.append( eval('lambda ' + pstring + ': ' + f[n],  self._globals))
                self._fnames.append(f[n])

                # "ODR" compatible function (for x-error bars), based on self.f
                self._odr_models.append( _odr.Model(eval('lambda p,x: self.f[n]('+pstring_odr+')', dict(self=self, n=n))))

            # Otherwise, just append it.
            else:
                self.f.append(f[n])
                self._fnames.append(f[n].__name__)

            # if bg[n] is a string, define a function on the fly.
            if isinstance(bg[n], str):
                self.bg.append(eval('lambda ' + pstring + ': ' + bg[n], self._globals))
                self._bgnames.append(bg[n])
            else:
                self.bg.append(bg[n])
                if bg[n] is None: self._bgnames.append("None")
                else:             self._bgnames.append(bg[n].__name__)

        # update the format of all the settings
        for k in list(self._settings.keys()): self[k] = self[k]

        # make sure we don't think our fit results are valid!
        self.clear_results()

Response: Updates the internal functions for the master list of the current ODR entry.


Instruction:
Given the following Python 3 function, write the documentation
def set_data(self, xdata=[1,2,3,4,5], ydata=[1.7,2,3,4,3], eydata=None, **kwargs):
        # SET UP DATA SETS TO MATCH EACH OTHER AND NUMBER OF FUNCTIONS

        # At this stage:
        # xdata,  ydata   'script', [1,2,3], [[1,2,3],'script'], ['script', [1,2,3]]
        # eydata, exdata  'script', [1,1,1], [[1,1,1],'script'], ['script', [1,1,1]], 3, [3,[1,2,3]], None

        # if xdata, ydata, or eydata are bare scripts, make them into lists
        if type(xdata)  is str: xdata  = [xdata]
        if type(ydata)  is str: ydata  = [ydata]
        if type(eydata) is str or _s.fun.is_a_number(eydata) or eydata is None: eydata = [eydata]
        #if type(exdata) is str or _s.fun.is_a_number(exdata) or exdata is None: exdata = [exdata]

        # xdata and ydata   ['script'], [1,2,3], [[1,2,3],'script'], ['script', [1,2,3]]
        # eydata            ['script'], [1,1,1], [[1,1,1],'script'], ['script', [1,1,1]], [3], [3,[1,2,3]], [None]

        # if the first element of data is a number, then this is a normal array
        if _s.fun.is_a_number(xdata[0]): xdata = [xdata]
        if _s.fun.is_a_number(ydata[0]): ydata = [ydata]

        # xdata and ydata   ['script'], [[1,2,3]], [[1,2,3],'script'], ['script', [1,2,3]]
        # eydata            ['script'], [1,1,1],   [[1,1,1],'script'], ['script', [1,1,1]], [3], [3,[1,2,3]], [None]

        # if the first element of eydata is a number, this could also just be an error bar value
        # Note: there is some ambiguity here, if the number of data sets equals the number of data points!
        if _s.fun.is_a_number(eydata[0]) and len(eydata) == len(ydata[0]): eydata = [eydata]
        #if _s.fun.is_a_number(exdata[0]) and len(exdata) == len(xdata[0]): exdata = [exdata]

        # xdata and ydata   ['script'], [[1,2,3]], [[1,2,3],'script'], ['script', [1,2,3]]
        # eydata            ['script'], [[1,1,1]], [[1,1,1],'script'], ['script', [1,1,1]], [3], [3,[1,2,3]], [None]

        # Inflate the x, ex, and ey data sets to match the ydata sets
        while len(xdata)  < len(ydata): xdata .append( xdata[0])
        while len(ydata)  < len(xdata): ydata .append( ydata[0])
        #while len(exdata) < len(xdata): exdata.append(exdata[0])
        while len(eydata) < len(ydata): eydata.append(eydata[0])

        # make sure these lists are the same length as the number of functions
        while len(ydata)  < len(self.f): ydata.append(ydata[0])
        while len(xdata)  < len(self.f): xdata.append(xdata[0])
        while len(eydata) < len(self.f): eydata.append(eydata[0])
        #while len(exdata) < len(self.f): exdata.append(exdata[0])

        # xdata and ydata   ['script','script'], [[1,2,3],[1,2,3]], [[1,2,3],'script'], ['script', [1,2,3]]
        # eydata            ['script','script'], [[1,1,1],[1,1,1]], [[1,1,1],'script'], ['script', [1,1,1]], [3,3], [3,[1,2,3]], [None,None]

        # Clean up exdata. If any element isn't None, the other None elements need
        # to be set to 0 so that ODR works.
#        if not exdata.count(None) == len(exdata):
#            # Search for and replace all None's with 0
#            for n in range(len(exdata)):
#                if exdata[n] == None: exdata[n] = 0
#

        # store the data, script, or whatever it is!
        self._set_xdata  = xdata
        self._set_ydata  = ydata
        self._set_eydata = eydata
        #self._set_exdata = exdata
        self._set_data_globals.update(kwargs)

        # set the eyscale to 1 for each data set
        self['scale_eydata'] = [1.0]*len(self._set_xdata)
        #self['scale_exdata'] = [1.0]*len(self._set_xdata)

        # Update the settings so they match the number of data sets.
        for k in self._settings.keys(): self[k] = self[k]

        # Plot if necessary
        if self['autoplot']: self.plot()

        return self

Response: This function will set the data of a specific entry in the log file.


Instruction:
Explain what the following Python 3 code does
def evaluate_script(self, script, **kwargs):
        self._set_data_globals.update(kwargs)
        return eval(script, self._set_data_globals)

Response:
Evaluates the supplied script (python-executable string).
        Useful for testing your scripts!

        globals already include all of numpy objects plus

        self = self
        f    = self.f
        bg   = self.bg

        and all the current guess parameters and constants

        kwargs are added to globals for script evaluation.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_data(self):
        # make sure we've done a "set data" call
        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return [[],[],[]]

        # update the globals with the current fit parameter guess values
        for n in range(len(self._pnames)): self._set_data_globals[self._pnames[n]] = self._pguess[n]
        for n in range(len(self._cnames)): self._set_data_globals[self._cnames[n]] = self._constants[n]

        # update the globals with x, y, and ey, and the functions
        self._set_data_globals['f']    = self.f
        self._set_data_globals['bg']   = self.bg
        self._set_data_globals['self'] = self

        # possibilities after calling set_data():
        # xdata and ydata   ['script','script'], [[1,2,3],[1,2,3]], [[1,2,3],'script'], ['script', [1,2,3]]
        # eydata            ['script','script'], [[1,1,1],[1,1,1]], [[1,1,1],'script'], ['script', [1,1,1]], [3,3], [3,[1,2,3]], [None,None]

        # make a copy
        xdata  = list(self._set_xdata)
        ydata  = list(self._set_ydata)
        eydata = list(self._set_eydata)
        #exdata = list(self._set_exdata)

        # make sure they're all lists of numpy arrays
        for n in range(len(xdata)):

            # For xdata, handle scripts or arrays
            if type(xdata[n]) is str: xdata[n] = self.evaluate_script(xdata[n], **self._set_data_globals)
            else:                     xdata[n] = _n.array(xdata[n])*1.0

        # update the globals
        self._set_data_globals['x'] = xdata

        # make sure they're all lists of numpy arrays
        for n in range(len(ydata)):

            # For ydata, handle scripts or arrays
            if type(ydata[n]) is str: ydata[n] = self.evaluate_script(ydata[n], **self._set_data_globals)
            else:                     ydata[n] = _n.array(ydata[n])*1.0

        # update the globals
        self._set_data_globals['y'] = ydata

        # make sure they're all lists of numpy arrays
        self._guessed_eydata = False
        for n in range(len(eydata)):

            # handle scripts
            if type(eydata[n]) is str:
                eydata[n] = self.evaluate_script(eydata[n], **self._set_data_globals)

            # handle None (possibly returned by script): take a visually-appealing guess at the error
            if eydata[n] is None:
                eydata[n] = _n.ones(len(xdata[n])) * (max(ydata[n])-min(ydata[n]))*0.05
                self._guessed_eydata = True

            # handle constant error bars (possibly returned by script)
            if _s.fun.is_a_number(eydata[n]):
                eydata[n] = _n.ones(len(xdata[n])) * eydata[n]

            # make it an array
            eydata[n] = _n.array(eydata[n]) * self["scale_eydata"][n]

#        # make sure they're all lists of numpy arrays
#        for n in range(len(exdata)):
#
#            # handle scripts
#            if type(exdata[n]) is str:
#                exdata[n] = self.evaluate_script(exdata[n], **self._set_data_globals)
#
#            # None is okay for exdata
#
#            # handle constant error bars (possibly returned by script)
#            if _s.fun.is_a_number(exdata[n]):
#                exdata[n] = _n.ones(len(xdata[n])) * exdata[n]
#
#            # make it an array
#            if not exdata[n] == None:
#                exdata[n] = _n.array(exdata[n]) * self["scale_exdata"][n]

        # return it
        return xdata, ydata, eydata

Response:
Returns the current xdata ydata eydata after set_data()
        has been run.


Instruction:
Can you generate the documentation for the following Python 3 function
def set_guess_to_fit_result(self):
        if self.results is None:
            print("No fit results to use! Run fit() first.")
            return

        # loop over the results and set the guess values
        for n in range(len(self._pguess)): self._pguess[n] = self.results[0][n]

        if self['autoplot']: self.plot()

        return self

Response: Set guess parameters to fit result.


Instruction:
Write a Python 3 function that can
return the data set of the current entry in the current object.

Response:
def get_processed_data(self, do_coarsen=True, do_trim=True):
        """
        This will coarsen and then trim the data sets according to settings.

        Returns processed xdata, ydata, eydata.

        Parameters
        ----------
        do_coarsen=True
            Whether we should coarsen the data
        do_trim=True
            Whether we should trim the data

        Settings
        --------
        xmin, xmax, ymin, ymax
            Limits on x and y data points for trimming.
        coarsen
            Break the data set(s) into this many groups of points, and average
            each group into one point, propagating errors.
        """

        # get the data
        xdatas, ydatas, eydatas = self.get_data()

        # get the trim limits (trimits)
        xmins   = self['xmin']
        xmaxs   = self['xmax']
        ymins   = self['ymin']
        ymaxs   = self['ymax']
        coarsen = self['coarsen']

        # make sure we have one limit for each data set
        if type(xmins)   is not list: xmins   = [xmins]  *len(xdatas)
        if type(xmaxs)   is not list: xmaxs   = [xmaxs]  *len(xdatas)
        if type(ymins)   is not list: ymins   = [ymins]  *len(xdatas)
        if type(ymaxs)   is not list: ymaxs   = [ymaxs]  *len(xdatas)
        if type(coarsen) is not list: coarsen = [coarsen]*len(xdatas)

        # this should cover all the data sets (dimensions should match!)
        xdata_massaged  = []
        ydata_massaged  = []
        eydata_massaged = []
        #exdata_massaged = []
        for n in range(len(xdatas)):

            x  = xdatas[n]
            y  = ydatas[n]
            ey = eydatas[n]
            #ex = exdatas[n]

            # coarsen the data
            if do_coarsen:
                x  =         _s.fun.coarsen_array(x,     self['coarsen'][n], 'mean')
                y  =         _s.fun.coarsen_array(y,     self['coarsen'][n], 'mean')
                ey = _n.sqrt(_s.fun.coarsen_array(ey**2, self['coarsen'][n], 'mean')/self['coarsen'][n])
#                if not ex == None:
#                    ex = _n.sqrt(_s.fun.coarsen_array(ex**2, self['coarsen'][n], 'mean')/self['coarsen'][n])

            if do_trim:
                # Create local mins and maxes
                xmin = xmins[n]
                ymin = ymins[n]
                xmax = xmaxs[n]
                ymax = ymaxs[n]

                # handle "None" limits
                if xmin is None: xmin = min(x)
                if xmax is None: xmax = max(x)
                if ymin is None: ymin = min(y)
                if ymax is None: ymax = max(y)

                # trim the data
                [xt, yt, eyt] = _s.fun.trim_data_uber([x, y, ey],
                                                      [x>=xmin, x<=xmax,
                                                       y>=ymin, y<=ymax])

                # Catch the over-trimmed case
                if(len(xt)==0):
                    self._error("\nDATA SET "+str(n)+": OOPS! OOPS! Specified limits (xmin, xmax, ymin, ymax) eliminate all data! Ignoring.")
                else:
                    x = xt
                    y = yt
                    ey = eyt
                    #ex = ext

            # store the result
            xdata_massaged.append(x)
            ydata_massaged.append(y)
            eydata_massaged.append(ey)
            #exdata_massaged.append(ex)

        return xdata_massaged, ydata_massaged, eydata_massaged


Instruction:
Can you generate the documentation for the following Python 3 function
def _massage_data(self):
        self._xdata_massaged, self._ydata_massaged, self._eydata_massaged = self.get_processed_data()

#        # Create the odr data.
#        self._odr_datas = []
#        for n in range(len(self._xdata_massaged)):
#            # Only exdata can be None; make sure it's zeros at least.
#            ex = self._exdata_massaged[n]
#            if ex == None: ex = _n.zeros(len(self._eydata_massaged[n]))
#            self._odr_datas.append(_odr.RealData(self._xdata_massaged[n],
#                                                 self._ydata_massaged[n],
#                                                 sx=ex,
#                                                 sy=self._eydata_massaged[n]))
        return self

Response: Processes the data and stores it.


Instruction:
Can you write a function in Python 3 where it
fits the data to the data and returns the results.

Response:
def fit(self, **kwargs):
        """
        This will try to determine fit parameters using scipy.optimize.leastsq
        algorithm. This function relies on a previous call of set_data() and
        set_functions().

        Notes
        -----
        results of the fit algorithm are stored in self.results.
        See scipy.optimize.leastsq for more information.

        Optional keyword arguments are sent to self.set() prior to
        fitting.
        """
        if len(self._set_xdata)==0 or len(self._set_ydata)==0:
            return self._error("No data. Please use set_data() prior to fitting.")
        if self._f_raw is None:
            return self._error("No functions. Please use set_functions() prior to fitting.")

        # Do the processing once, to increase efficiency
        self._massage_data()

        # Send the keyword arguments to the settings
        self.set(**kwargs)

        # do the actual optimization
        self.results = _opt.leastsq(self._studentized_residuals_concatenated, self._pguess, full_output=1)

        # plot if necessary
        if self['autoplot']: self.plot()

        return self


Instruction:
Can you implement a function in Python 3 that
turns parameters to constants. As arguments, parameters must be strings. As keyword arguments, they can be set at the same time. Note this will NOT work when specifying a non-string fit function, because there is no flexibility in the number of arguments. To get around this, suppose you've defined a function stuff(x,a,b). Instead of sending the stuff object to self.set_functions() directly, make it a string function, e.g.: self.set_functions('stuff(x,a,b)', 'a,b', stuff=stuff)

Response:
def fix(self, *args, **kwargs):
        """
        Turns parameters to constants. As arguments, parameters must be strings.
        As keyword arguments, they can be set at the same time.

        Note this will NOT work when specifying a non-string fit function,
        because there is no flexibility in the number of arguments. To get
        around this, suppose you've defined a function stuff(x,a,b). Instead
        of sending the stuff object to self.set_functions() directly, make it
        a string function, e.g.:

          self.set_functions('stuff(x,a,b)', 'a,b', stuff=stuff)
        """

        # first set all the keyword argument values
        self.set(**kwargs)

        # get everything into one big list
        pnames = list(args) + list(kwargs.keys())

        # move each pname to the constants
        for pname in pnames:
            if not pname in self._pnames:
                self._error("Naughty. '"+pname+"' is not a valid fit parameter name.")

            else:
                n = self._pnames.index(pname)

                # use the fit result if it exists
                if self.results: value = self.results[0][n]

                # otherwise use the guess value
                else: value = self._pguess[n]

                # make the switcheroo
                if type(self._pnames)    is not list: self._pnames    = list(self._pnames)
                if type(self._pguess)    is not list: self._pguess    = list(self._pguess)
                if type(self._cnames)    is not list: self._cnames    = list(self._cnames)
                if type(self._constants) is not list: self._constants = list(self._constants)
                self._pnames.pop(n)
                self._pguess.pop(n)
                self._cnames.append(pname)
                self._constants.append(value)

                # update
                self._update_functions()

        return self


Instruction:
Write a Python 3 script for
turning a constant into a parameter. As arguments, parameters must be strings. As keyword arguments, they can be set at the same time.

Response:
def free(self, *args, **kwargs):
        """
        Turns a constant into a parameter. As arguments, parameters must be strings.
        As keyword arguments, they can be set at the same time.
        """
        # first set all the keyword argument values
        self.set(**kwargs)

        # get everything into one big list
        cnames = list(args) + list(kwargs.keys())

        # move each pname to the constants
        for cname in cnames:

            if not cname in self._cnames:
                self._error("Naughty. '"+cname+"' is not a valid constant name.")

            else:
                n = self._cnames.index(cname)

                # make the switcheroo
                if type(self._pnames)    is not list: self._pnames    = list(self._pnames)
                if type(self._pguess)    is not list: self._pguess    = list(self._pguess)
                if type(self._cnames)    is not list: self._cnames    = list(self._cnames)
                if type(self._constants) is not list: self._constants = list(self._constants)
                self._pnames.append(self._cnames.pop(n))
                self._pguess.append(self._constants.pop(n))

                # update
                self._update_functions()

        return self


Instruction:
How would you explain what the following Python 3 function does
def _evaluate_all_functions(self, xdata, p=None):
        if p is None: p = self.results[0]

        output = []
        for n in range(len(self.f)):
            output.append(self._evaluate_f(n, self._xdata_massaged[n], p) )

        return output

Response: This function evaluates all functions and returns a list of function outputs given the stored data sets.


Instruction:
Given the following Python 3 function, write the documentation
def _evaluate_f(self, n, xdata, p=None):
        # by default, use the fit values, otherwise, use the guess values.
        if   p is None and self.results is not None: p = self.results[0]
        elif p is None and self.results is None:     p = self._pguess

        # assemble the arguments for the function
        args = (xdata,) + tuple(p)

        # evaluate this function.
        return self.f[n](*args)

Response: Evaluates a single function n for arbitrary xdata and p tuple.


Instruction:
Write a Python 3 script to
evaluate a single background function n for arbitrary xdata and p tuple.

Response:
def _evaluate_bg(self, n, xdata, p=None):
        """
        Evaluates a single background function n for arbitrary xdata and p tuple.

        p=None means use the fit results
        """
        # by default, use the fit values, otherwise, use the guess values.
        if   p is None and self.results is not None: p = self.results[0]
        elif p is None and self.results is None:     p = self._pguess

        # return None if there is no background function
        if self.bg[n] is None: return None

        # assemble the arguments for the function
        args = (xdata,) + tuple(p)

        # evaluate the function
        return self.bg[n](*args)


Instruction:
Write a Python 3 script for
formatting the value of a key - value pair as a string.

Response:
def _format_value_error(self, v, e, pm=" +/- "):
        """
        Returns a string v +/- e with the right number of sig figs.
        """
        # If we have weird stuff
        if not _s.fun.is_a_number(v) or not _s.fun.is_a_number(e) \
            or v in [_n.inf, _n.nan, _n.NAN] or e in [_n.inf, _n.nan, _n.NAN]:
            return str(v)+pm+str(e)

        # Normal values.
        try:
            sig_figs = -int(_n.floor(_n.log10(abs(e))))+1
            return str(_n.round(v, sig_figs)) + pm + str(_n.round(e, sig_figs))

        except:
            return str(v)+pm+str(e)


Instruction:
Can you tell what is the following Python 3 function doing
def _studentized_residuals_fast(self, p=None):
        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return

        if p is None:
            if self.results is None: p = self._pguess
            else:                    p = self.results[0]

        # evaluate the function for all the data, returns a list!
        f = self._evaluate_all_functions(self._xdata_massaged, p)

        # get the full residuals list
        residuals = []
        for n in range(len(f)):
            numerator = self._ydata_massaged[n]-f[n]
            denominator = _n.absolute(self._eydata_massaged[n])
            residuals.append(numerator/denominator)
        return residuals

Response: This function returns a list of studentized residuals for all the data.


Instruction:
Explain what the following Python 3 code does
def chi_squareds(self, p=None):
        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return None

        if p is None: p = self.results[0]

        # get the residuals
        rs = self.studentized_residuals(p)

        # Handle the none case
        if rs == None: return None

        # square em and sum em.
        cs = []
        for r in rs: cs.append(sum(r**2))
        return cs

Response: Returns a list of chi squared for each data set. Also uses ydata_massaged.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def chi_squared(self, p=None):
        chi2s = self.chi_squareds(p)
        if chi2s == None: return None

        return sum(self.chi_squareds(p))

Response: Returns the total chi squared of all massaged data sets.


Instruction:
Given the following Python 3 function, write the documentation
def degrees_of_freedom(self):
        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return None

        # Temporary hack: get the studentized residuals, which uses the massaged data
        # This should later be changed to get_massaged_data()
        r = self.studentized_residuals()

        # Happens if data / functions not defined
        if r == None: return

        # calculate the number of points
        N = 0.0
        for i in range(len(r)): N += len(r[i])

        return N-len(self._pnames)

Response: Returns the number of degrees of freedom.


Instruction:
How would you explain what the following Python 3 function does
def reduced_chi_squareds(self, p=None):
        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return None

        if p is None: p = self.results[0]
        r = self.studentized_residuals(p)

        # In case it's not possible to calculate
        if r is None: return

        # calculate the number of points
        N = 0
        for i in range(len(r)): N += len(r[i])

        # degrees of freedom
        dof_per_point = self.degrees_of_freedom()/N

        for n in range(len(r)):
            r[n] = sum(r[n]**2)/(len(r[n])*dof_per_point)

        return r

Response: Returns the reduced chi squared for each massaged data set.


Instruction:
Explain what the following Python 3 code does
def reduced_chi_squared(self, p=None):

        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return None
        if p is None: p = self.results[0]

        chi2 = self.chi_squared(p)
        dof  = self.degrees_of_freedom()
        if not _s.fun.is_a_number(chi2) or not _s.fun.is_a_number(dof):
            return None

        return _n.divide(self.chi_squared(p), self.degrees_of_freedom())

Response: Returns the reduced chi squared for all massaged data sets.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def plot(self, **kwargs):

        # Make sure there is data to plot.
        if len(self._set_xdata)==0 or len(self._set_ydata)==0: return self

        # Make sure the figures is a list
        if not self.figures == None and not type(self.figures) == list:
            self.figures = [self.figures]

        # Get the trimmed and full processed data
        xts, yts, eyts = self.get_processed_data()
        xas, yas, eyas = self.get_processed_data(do_trim=False)

        # update settings
        for k in kwargs: self[k] = kwargs[k]

        # Calculate all studentized residuals
        if len(self.f) > 0: rt = self.studentized_residuals()

        # make a new figure for each data set
        for n in range(len(self._set_xdata)):
            xt = xts[n]
            xa = xas[n]
            yt = yts[n]
            ya = yas[n]
            eyt = eyts[n]
            eya = eyas[n]
            #ext = exts[n]
            eyt = eyts[n]

            # get the next figure
            if self.figures == None: fig = _p.figure(self['first_figure']+n)
            else: fig = self.figures[n]

            # turn off interactive mode and clear the figure
            _p.ioff()
            fig.clear()

            # set up two axes. One for data and one for residuals.
            a1 = fig.add_subplot(211)            # Residuals
            a2 = fig.add_subplot(212, sharex=a1) # Data
            a1.set_position([0.15, 0.72, 0.75, 0.15])
            a2.set_position([0.15, 0.10, 0.75, 0.60])

            # set the scales
            a1.set_xscale(self['xscale'][n])
            a2.set_xscale(self['xscale'][n])
            a2.set_yscale(self['yscale'][n])

            # Get the function xdata
            fxa = self._get_xdata_for_function(n,xa)
            fxt = self._get_xdata_for_function(n,xt)

            # get the values to subtract from ydata if subtracting the background
            if self['subtract_bg'][n] and not self.bg[n] is None:

                # if we have a fit, use that for the background
                if self.results: p = self.results[0]
                else:            p = self._pguess

                # Get the background data
                d_ya  = self._evaluate_bg(n, xa,  p)
                d_fya = self._evaluate_bg(n, fxa, p)
                d_yt  = self._evaluate_bg(n, xt,  p)
                d_fyt = self._evaluate_bg(n, fxt, p)

            # Otherwise just make some zero arrays
            else:
                d_ya  = 0*xa
                d_fya = 0*fxa
                d_yt  = 0*xt
                d_fyt = 0*fxt

            # PLOT DATA FIRST

            # If we're supposed to, add the "all" data and function
            if self['plot_all_data'][n]:

                # Make it faint.
                style_data  = dict(self['style_data' ][n]); style_data ['alpha'] = 0.3

                if self['plot_errors'][n]: a2.errorbar(xa, ya-d_ya, eya, zorder=5, **style_data)
                else:                      a2.plot    (xa, ya-d_ya,      zorder=5, **style_data)

            # add the trimmed data
            if self['plot_errors'][n]:     a2.errorbar(xt, yt-d_yt, eyt, zorder=7, **self['style_data'][n])
            else:                          a2.plot(    xt, yt-d_yt,      zorder=7, **self['style_data'][n])

            # Zoom on just the data for now
            _s.tweaks.auto_zoom(axes=a2, draw=False)

            # PLOT FUNCTIONS

            if n < len(self.f): # If there are any functions to plot

                # Plot the GUESS under the fit
                if self['plot_guess'][n]:

                    # FULL GUESS
                    if self['plot_all_data'][n]:

                        # Make it faint.
                        style_guess = dict(self['style_guess'][n]); style_guess['alpha'] = 0.3

                        # FULL background GUESS
                        if self['plot_bg'][n] and self.bg[n] is not None:
                            bg_gya = self._evaluate_bg(n, fxa, self._pguess)
                            a2.plot(fxa, bg_gya-d_fya, zorder=9, **style_guess)

                        # FULL guess
                        gya = self._evaluate_f (n, fxa, self._pguess)
                        a2.plot(fxa, gya-d_fya, zorder=9, **style_guess)

                        # Update the trimmed datas so that the points line up
                        [fxt] = _s.fun.trim_data_uber([fxt], [fxt>=min(xt), fxt<=max(xt)])

                    # TRIMMED GUESS BACKGROUND

                    # TRIMMED guess background curve
                    if self['plot_bg'][n] and self.bg[n] is not None:
                        bg_gyt = self._evaluate_bg(n, fxt, self._pguess)
                        a2.plot(fxt, bg_gyt-d_fyt, zorder=9, **self['style_guess'][n])

                    # TRIMMED main guess curve
                    gyt = self._evaluate_f (n, fxt, self._pguess)
                    a2.plot(fxt, gyt-d_fyt, zorder=9, **self['style_guess'][n])

                # Plot the FIT if there is one
                if not self.results == None:

                    # FULL FIT
                    if self['plot_all_data'][n]:

                        # Make it faint.
                        style_fit = dict(self['style_fit'][n]); style_fit['alpha'] = 0.3

                        # FULL background fit
                        if self['plot_bg'][n] and self.bg[n] is not None:
                            bg_fya = self._evaluate_bg(n, fxa, self.results[0])
                            a2.plot(fxa, bg_fya-d_fya, zorder=10, **style_fit)

                        # FULL fit
                        fya = self._evaluate_f (n, fxa, self.results[0])
                        a2.plot(fxa, fya-d_fya, zorder=10, **style_fit)

                        # Update the trimmed datas so that the points line up
                        [fxt] = _s.fun.trim_data_uber([fxt], [fxt>=min(xt), fxt<=max(xt)])

                    # TRIMMED FIT BACKGROUND
                    if self['plot_bg'][n] and self.bg[n] is not None:
                        bg_fyt = self._evaluate_bg(n, fxt, self.results[0])
                        a2.plot(fxt, bg_fyt-d_fyt, zorder=10, **self['style_fit'][n])

                    # TRIMMED main curve
                    fyt = self._evaluate_f(n, fxt, self.results[0])
                    a2.plot(fxt, fyt-d_fyt, zorder=10, **self['style_fit'][n])

                if self['plot_guess_zoom'][n]: _s.tweaks.auto_zoom(axes=a2, draw=False)

            # plot the residuals only if there are functions defined
            if len(self.f):

                # If we're supposed to also plot all the data, we have to
                # Manually calculate the residuals. Clunky, I know.
                if self['plot_all_data'][n]:

                    # Figure out what guy to use for the residuals
                    if self.results is None:
                        p = self._pguess
                        style = style_guess
                    else:
                        p = self.results[0]
                        style = style_fit

                    # Calculate them
                    ra = (ya-self._evaluate_f(n, xa, p))/eya

                    # style_data, style_guess, and style_fit should already be faint
                    a1.errorbar(xa, ra, _n.ones(len(ra)), **style_data)

                    # Put the line on top
                    a1.plot([min(xa), max(xa)], [0,0], **style)

                # Figure out what style to use for the line
                if self.results is None: style = self['style_guess'][n]
                else:                    style = self['style_fit'  ][n]

                # Main residuals plot
                a1.errorbar (xt, rt[n], _n.ones(len(xt)), **self['style_data'][n])
                a1.plot([min(xt), max(xt)], [0,0], **style)

            # Tidy up
            yticklabels = a1.get_yticklabels()
            for m in range(2,len(yticklabels)-2): yticklabels[m].set_visible(False)
            for m in a1.get_xticklabels(): m.set_visible(False)

            # Add labels to the axes
            if self['xlabel'][n] is None: a2.set_xlabel('xdata['+str(n)+']')
            else:                         a2.set_xlabel(self['xlabel'][n])
            if self['ylabel'][n] is None:
                ylabel='ydata['+str(n)+']'
                if self['subtract_bg'][n] and self.bg[n] is not None:
                    ylabel=ylabel+' - bg['+str(n)+']'
                a2.set_ylabel(ylabel)
            else:                         a2.set_ylabel(self['ylabel'][n])
            a1.set_ylabel('Studentized\nResiduals')

            # Assemble the title
            wrap = 80
            indent = '      '

            # Include the function names if available
            if n < len(self.f):
                t = _textwrap.fill('Function ('+str(n)+'/'+str(len(self._fnames)-1)+'): y = '+self._fnames[n], wrap, subsequent_indent=indent)
            else:
                t = "No functions defined. Use set_functions()."

            if len(self._cnames):
                t1 = "Constants: "
                for i in range(len(self._cnames)):
                    t1 = t1 + self._cnames[i] + "={:G}, ".format(self._constants[i])
                t = t + '\n' + _textwrap.fill(t1, wrap, subsequent_indent=indent)

            if self.results and not self.results[1] is None:
                t1 = "Fit: "
                for i in range(len(self._pnames)):
                    t1 = t1 + self._pnames[i] + "={:s}, ".format(self._format_value_error(self.results[0][i], _n.sqrt(self.results[1][i][i]), '$\pm$'))
                t1 = t1 + '$\chi^2_r$={} ({} DOF)'.format(
                        self._format_value_error(self.reduced_chi_squared(), _n.sqrt(_n.divide(2.0,self.degrees_of_freedom())), '$\pm$'),
                        int(self.degrees_of_freedom()))

                t = t + '\n' + _textwrap.fill(t1, wrap, subsequent_indent=indent)

            elif self.results:
                t1 = "Fit did not converge: "
                for i in range(len(self._pnames)):
                    t1 = t1 + self._pnames[i] + "={:8G}$, "
                t = t + '\n' + _textwrap.fill(t1, wrap, subsequent_indent=indent)

            a1.set_title(t, fontsize=10, ha='left', position=(0,1))

            # turn back to interactive and show the plots.
            _p.ion()
            if self.figures == None:
                _p.draw()
                _p.show()

        # End of new figure for each data set loop
        return self

Response: Plots the data for the current set of items.


Instruction:
Can you create a Python 3 function that
generates the xdata for plotting the function n.

Response:
def _get_xdata_for_function(self, n, xdata):
        """
        Generates the x-data for plotting the function.

        Parameters
        ----------
        n
            Which data set we're using
        xdata
            Data set upon which to base this

        Returns
        -------
        float
        """

        # Use the xdata itself for the function
        if self['fpoints'][n] in [None, 0]: return _n.array(xdata)

        # Otherwise, generate xdata with the number of fpoints

        # do exponential ranging if xscale is log
        if self['xscale'][n] == 'log':
            return _n.logspace(_n.log10(min(xdata)), _n.log10(max(xdata)),
                               self['fpoints'][n], True, 10.0)

        # otherwise do linear spacing
        else:
            return _n.linspace(min(xdata), max(xdata), self['fpoints'][n])


Instruction:
Write a Python 3 script for
removing xmin xmax ymin ymax.

Response:
def untrim(self, n='all'):
        """
        Removes xmin, xmax, ymin, and ymax.

        Parameters
        ----------
        n='all'
            Which data set to perform this action upon. 'all' means all data
            sets, or you can specify a list.
        """
        if len(self._set_xdata)==0 or len(self._set_ydata)==0:
            self._error("No data. Please use set_data() and plot() prior to zooming.")
            return

        if   _s.fun.is_a_number(n): n = [n]
        elif isinstance(n,str):     n = list(range(len(self._set_xdata)))

        # loop over the specified plots
        for i in n:
            self['xmin'][i] = None
            self['xmax'][i] = None
            self['ymin'][i] = None
            self['ymax'][i] = None

        # now show the update.
        self.clear_results()
        if self['autoplot']: self.plot()
        return self


Instruction:
How would you explain what the following Python 3 function does
def zoom(self, n='all', xfactor=2.0, yfactor=2.0):
        if len(self._set_xdata)==0 or len(self._set_ydata)==0:
            self._error("No data. Please use set_data() and plot() prior to zooming.")
            return

        # get the data
        xdata, ydata, eydata = self.get_data()

        if   _s.fun.is_a_number(n): n = [n]
        elif isinstance(n,str):     n = list(range(len(xdata)))

        # loop over the specified plots
        for i in n:
            fig = self['first_figure']+i
            try:
                xmin, xmax = _p.figure(fig).axes[1].get_xlim()
                xc = 0.5*(xmin+xmax)
                xs = 0.5*abs(xmax-xmin)
                self['xmin'][i] = xc - xfactor*xs
                self['xmax'][i] = xc + xfactor*xs

                ymin, ymax = _p.figure(fig).axes[1].get_ylim()
                yc = 0.5*(ymin+ymax)
                ys = 0.5*abs(ymax-ymin)
                self['ymin'][i] = yc - yfactor*ys
                self['ymax'][i] = yc + yfactor*ys
            except:
                self._error("Data "+str(fig)+" is not currently plotted.")

        # now show the update.
        self.clear_results()
        if self['autoplot']: self.plot()

        return self

Response: This will scale the chosen data set s plot range by the specified xfactor and yfactor respectively and set the trim limits xmin xmax ymin ymax accordingly


Instruction:
Can you tell what is the following Python 3 function doing
def ginput(self, data_set=0, **kwargs):
        # this will temporarily fix the deprecation warning
        import warnings
        import matplotlib.cbook
        warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation)

        _s.tweaks.raise_figure_window(data_set+self['first_figure'])
        return _p.ginput(**kwargs)

Response: Returns the value of ginput.


Instruction:
How would you implement a function in Python 3 that
matches data sets x and y.

Response:
def _match_data_sets(x,y):
    """
    Makes sure everything is the same shape. "Intelligently".
    """
    # Handle the None for x or y
    if x is None:
        # If x is none, y can be either [1,2] or [[1,2],[1,2]]
        if _fun.is_iterable(y[0]):
            # make an array of arrays to match
            x = []
            for n in range(len(y)):
                x.append(list(range(len(y[n]))))
        else: x = list(range(len(y)))

    if y is None:
        # If x is none, y can be either [1,2] or [[1,2],[1,2]]
        if _fun.is_iterable(x[0]):
            # make an array of arrays to match
            y = []
            for n in range(len(x)):
                y.append(list(range(len(x[n]))))
        else: y = list(range(len(x)))

    # At this point they should be matched, but may still be 1D
    # Default behavior: if all elements are numbers in both, assume they match
    if _fun.elements_are_numbers(x) and _fun.elements_are_numbers(y):
        x = [x]
        y = [y]

    # Second default behavior: shared array [1,2,3], [[1,2,1],[1,2,1]] or vis versa
    if _fun.elements_are_numbers(x) and not _fun.elements_are_numbers(y): x = [x]*len(y)
    if _fun.elements_are_numbers(y) and not _fun.elements_are_numbers(x): y = [y]*len(x)

    # Clean up any remaining Nones
    for n in range(len(x)):
        if x[n] is None: x[n] = list(range(len(y[n])))
        if y[n] is None: y[n] = list(range(len(x[n])))

    return x, y


Instruction:
Create a Python 3 function for
inflating ex to match the dimensionality of x intelligently.

Response:
def _match_error_to_data_set(x, ex):
    """
    Inflates ex to match the dimensionality of x, "intelligently".
    x is assumed to be a 2D array.
    """
    # Simplest case, ex is None or a number
    if not _fun.is_iterable(ex):

        # Just make a matched list of Nones
        if ex is None: ex = [ex]*len(x)

        # Make arrays of numbers
        if _fun.is_a_number(ex):
            value = ex # temporary storage
            ex    = []
            for n in range(len(x)):
                ex.append([value]*len(x[n]))

    # Otherwise, ex is iterable

    # Default behavior: If the elements are all numbers and the length matches
    # that of the first x-array, assume this is meant to match all the x
    # data sets
    if _fun.elements_are_numbers(ex) and len(ex) == len(x[0]): ex = [ex]*len(x)

    # The user may specify a list of some iterable and some not. Assume
    # in this case that at least the lists are the same length
    for n in range(len(x)):
        # do nothing to the None's
        # Inflate single numbers to match
        if _fun.is_a_number(ex[n]): ex[n] = [ex[n]]*len(x[n])

    return ex


Instruction:
How would you explain what the following Python 3 function does
def complex_data(data, edata=None, draw=True, **kwargs):
    _pylab.ioff()

    # generate the data the easy way
    try:
        rdata = _n.real(data)
        idata = _n.imag(data)
        if edata is None:
            erdata = None
            eidata = None
        else:
            erdata = _n.real(edata)
            eidata = _n.imag(edata)

    # generate the data the hard way.
    except:
        rdata = []
        idata = []
        if edata is None:
            erdata = None
            eidata = None
        else:
            erdata = []
            eidata = []

        for n in range(len(data)):
            rdata.append(_n.real(data[n]))
            idata.append(_n.imag(data[n]))

            if not edata is None:
                erdata.append(_n.real(edata[n]))
                eidata.append(_n.imag(edata[n]))

    if 'xlabel' not in kwargs:    kwargs['xlabel'] = 'Real'
    if 'ylabel' not in kwargs:    kwargs['ylabel'] = 'Imaginary'

    xy_data(rdata, idata, eidata, erdata, draw=False, **kwargs)

    if draw:
        _pylab.ion()
        _pylab.draw()
        _pylab.show()

Response: Generate the imaginary vs real complex data for the internal class.


Instruction:
Implement a function in Python 3 to
generate data and send to a single databox

Response:
def complex_databoxes(ds, script='d[1]+1j*d[2]', escript=None, **kwargs):
    """
    Uses databoxes and specified script to generate data and send to
    spinmob.plot.complex_data()

    Parameters
    ----------
    ds
        List of databoxes
    script='d[1]+1j*d[2]'
        Complex-valued script for data array.
    escript=None
        Complex-valued script for error bars

    See spinmob.plot.complex.data() for additional optional keyword arguments.
    See spinmob.data.databox.execute_script() for more information about scripts.
    """
    datas  = []
    labels = []
    if escript is None: errors = None
    else:             errors = []

    for d in ds:
        datas.append(d(script))
        labels.append(_os.path.split(d.path)[-1])
        if not escript is None: errors.append(d(escript))

    complex_data(datas, errors, label=labels, **kwargs)

    if "draw" in kwargs and not kwargs["draw"]: return

    _pylab.ion()
    _pylab.draw()
    _pylab.show()

    return ds


Instruction:
How would you explain what the following Python 3 function does
def complex_files(script='d[1]+1j*d[2]', escript=None, paths=None, **kwargs):
    ds = _data.load_multiple(paths=paths)

    if len(ds) == 0: return

    if 'title' not in kwargs: kwargs['title'] = _os.path.split(ds[0].path)[0]

    return complex_databoxes(ds, script=script, **kwargs)

Response: Load a set of complex files and plots them in the real - imaginary plane.


Instruction:
How would you code a function in Python 3 to
return a new object that can be used to plot a complex function over a specified range.

Response:
def complex_function(f='1.0/(1+1j*x)', xmin=-1, xmax=1, steps=200, p='x', g=None, erange=False, **kwargs):
    """
    Plots function(s) in the complex plane over the specified range.

    Parameters
    ----------
    f='1.0/(1+1j*x)'
        Complex-valued function or list of functions to plot.
        These can be string functions or single-argument python functions;
        additional globals can be supplied by g.
    xmin=-1, xmax=1, steps=200
        Range over which to plot and how many points to plot
    p='x'
        If using strings for functions, p is the independent parameter name.
    g=None
        Optional dictionary of extra globals. Try g=globals()!
    erange=False
        Use exponential spacing of the x data?

    See spinmob.plot.xy.data() for additional optional keyword arguments.
    """
    kwargs2 = dict(xlabel='Real', ylabel='Imaginary')
    kwargs2.update(kwargs)
    function(f, xmin, xmax, steps, p, g, erange, plotter=xy_data, complex_plane=True, draw=True, **kwargs2)


Instruction:
Can you implement a function in Python 3 that
plots the magnitude and phase of complex ydata vs xdata. Parameters ---------- xdata Real-valued x-axis data ydata Complex-valued y-axis data eydata=None Complex-valued y-error exdata=None Real-valued x-error xscale='linear' 'log' or 'linear' scale of the x axis mscale='linear' 'log' or 'linear' scale of the magnitude axis pscale='linear' 'log' or 'linear' scale of the phase axis mlabel='Magnitude' y-axis label for magnitude plot plabel='Phase' y-axis label for phase plot phase='degrees' 'degrees' or 'radians' for the phase axis figure='gcf' Plot on the specified figure instance or 'gcf' for current figure. clear=1 Clear the figure? draw=True Draw the figure when complete? See spinmob.plot.xy.data() for additional optional keyword arguments.

Response:
def magphase_data(xdata, ydata, eydata=None, exdata=None, xscale='linear', mscale='linear', pscale='linear', mlabel='Magnitude', plabel='Phase', phase='degrees', figure='gcf', clear=1, draw=True,  **kwargs):
    """
    Plots the magnitude and phase of complex ydata vs xdata.

    Parameters
    ----------
    xdata
        Real-valued x-axis data
    ydata
        Complex-valued y-axis data
    eydata=None
        Complex-valued y-error
    exdata=None
        Real-valued x-error
    xscale='linear'
        'log' or 'linear' scale of the x axis
    mscale='linear'
        'log' or 'linear' scale of the magnitude axis
    pscale='linear'
        'log' or 'linear' scale of the phase axis
    mlabel='Magnitude'
        y-axis label for magnitude plot
    plabel='Phase'
        y-axis label for phase plot
    phase='degrees'
        'degrees' or 'radians' for the phase axis
    figure='gcf'
        Plot on the specified figure instance or 'gcf' for current figure.
    clear=1
        Clear the figure?
    draw=True
        Draw the figure when complete?

    See spinmob.plot.xy.data() for additional optional keyword arguments.
    """
    _pylab.ioff()

    # set up the figure and axes
    if figure == 'gcf': f = _pylab.gcf()
    if clear: f.clear()
    axes1 = _pylab.subplot(211)
    axes2 = _pylab.subplot(212,sharex=axes1)

    # Make sure the dimensionality of the data sets matches
    xdata, ydata = _match_data_sets(xdata, ydata)
    exdata = _match_error_to_data_set(xdata, exdata)
    eydata = _match_error_to_data_set(ydata, eydata)

    # convert to magnitude and phase
    m  = []
    p  = []
    em = []
    ep = []

    # Note this is a loop over data sets, not points.
    for l in range(len(ydata)):
        m.append(_n.abs(ydata[l]))
        p.append(_n.angle(ydata[l]))
        # get the mag - phase errors
        if eydata[l] is None:
            em.append(None)
            ep.append(None)
        else:
            er = _n.real(eydata[l])
            ei = _n.imag(eydata[l])
            em.append(0.5*((er+ei) + (er-ei)*_n.cos(p[l]))      )
            ep.append(0.5*((er+ei) - (er-ei)*_n.cos(p[l]))/m[l] )

        # convert to degrees
        if phase=='degrees':
            p[-1] = p[-1]*180.0/_n.pi
            if not ep[l] is None:
                ep[l] = ep[l]*180.0/_n.pi

    if phase=='degrees':         plabel = plabel + " (degrees)"
    else:                        plabel = plabel + " (radians)"
    if 'xlabel' in kwargs: xlabel=kwargs.pop('xlabel')
    else:                        xlabel=''
    if 'ylabel' in kwargs: kwargs.pop('ylabel')

    if 'autoformat' not in kwargs: kwargs['autoformat'] = True

    autoformat = kwargs['autoformat']
    kwargs['autoformat'] = False
    kwargs['xlabel'] = ''
    xy_data(xdata, m, em, exdata, ylabel=mlabel, axes=axes1, clear=0, xscale=xscale, yscale=mscale, draw=False, **kwargs)

    kwargs['autoformat'] = autoformat
    kwargs['xlabel'] = xlabel
    xy_data(xdata, p, ep, exdata, ylabel=plabel, axes=axes2, clear=0, xscale=xscale, yscale=pscale, draw=False, **kwargs)

    axes2.set_title('')

    if draw:
        _pylab.ion()
        _pylab.draw()
        _pylab.show()


Instruction:
Given the following Python 3 function, write the documentation
def magphase_databoxes(ds, xscript=0, yscript='d[1]+1j*d[2]', eyscript=None, exscript=None, g=None, **kwargs):
    databoxes(ds, xscript, yscript, eyscript, exscript, plotter=magphase_data, g=g, **kwargs)

Response: Generate data and plot the complex magnitude and phase databoxes.


Instruction:
Explain what the following Python 3 code does
def magphase_files(xscript=0, yscript='d[1]+1j*d[2]', eyscript=None, exscript=None, paths=None, g=None, **kwargs):
    return files(xscript, yscript, eyscript, exscript, plotter=magphase_databoxes, paths=paths, g=g, **kwargs)

Response: Returns a bunch of files that will be plotted by the specified scripts.


Instruction:
Given the following Python 3 function, write the documentation
def magphase_function(f='1.0/(1+1j*x)', xmin=-1, xmax=1, steps=200, p='x', g=None, erange=False, **kwargs):
    function(f, xmin, xmax, steps, p, g, erange, plotter=magphase_data, **kwargs)

Response: Returns a new object that provides the magnitude and phase of a single - argument function.


Instruction:
Explain what the following Python 3 code does
def realimag_data(xdata, ydata, eydata=None, exdata=None, xscale='linear', rscale='linear', iscale='linear', rlabel='Real', ilabel='Imaginary', figure='gcf', clear=1, draw=True, **kwargs):
    _pylab.ioff()

    # Make sure the dimensionality of the data sets matches
    xdata, ydata = _match_data_sets(xdata, ydata)
    exdata = _match_error_to_data_set(xdata, exdata)
    eydata = _match_error_to_data_set(ydata, eydata)

    # convert to real imag, and get error bars
    rdata = []
    idata = []
    erdata = []
    eidata = []
    for l in range(len(ydata)):
        rdata.append(_n.real(ydata[l]))
        idata.append(_n.imag(ydata[l]))

        if eydata[l] is None:
            erdata.append(None)
            eidata.append(None)
        else:
            erdata.append(_n.real(eydata[l]))
            eidata.append(_n.imag(eydata[l]))

    # set up the figure and axes
    if figure == 'gcf': f = _pylab.gcf()
    if clear: f.clear()
    axes1 = _pylab.subplot(211)
    axes2 = _pylab.subplot(212,sharex=axes1)

    if 'xlabel' in kwargs  : xlabel=kwargs.pop('xlabel')
    else:                          xlabel=''
    if 'ylabel' in kwargs  : kwargs.pop('ylabel')

    if 'tall' not in kwargs:         kwargs['tall'] = False
    if 'autoformat' not in kwargs:   kwargs['autoformat'] = True

    autoformat = kwargs['autoformat']
    kwargs['autoformat'] = False
    kwargs['xlabel'] = ''
    xy_data(xdata, rdata, eydata=erdata, exdata=exdata, ylabel=rlabel, axes=axes1, clear=0, xscale=xscale, yscale=rscale, draw=False, **kwargs)

    kwargs['autoformat'] = autoformat
    kwargs['xlabel'] = xlabel
    xy_data(xdata, idata, eydata=eidata, exdata=exdata, ylabel=ilabel, axes=axes2, clear=0, xscale=xscale, yscale=iscale, draw=False, **kwargs)

    axes2.set_title('')

    if draw:
        _pylab.ion()
        _pylab.draw()
        _pylab.show()

Response: Returns a list of real and imaginary parts of a complex data set.


Instruction:
Here you have a function in Python 3, explain what it does
def realimag_databoxes(ds, xscript=0, yscript="d[1]+1j*d[2]", eyscript=None, exscript=None, g=None, **kwargs):
    databoxes(ds, xscript, yscript, eyscript, exscript, plotter=realimag_data, g=g, **kwargs)

Response: Generate real and imaginary xdata versus xdata.


Instruction:
Make a summary of the following Python 3 code
def realimag_files(xscript=0, yscript="d[1]+1j*d[2]", eyscript=None, exscript=None, paths=None, g=None, **kwargs):
    return files(xscript, yscript, eyscript, exscript, plotter=realimag_databoxes, paths=paths, g=g, **kwargs)

Response: This function will load a bunch of data files generate data based on the supplied scripts and then plot the xdata s real and imaginary parts versus xdata.


Instruction:
Can you implement a function in Python 3 that
returns a new object that provides real and imaginary parts of a spinmob.

Response:
def realimag_function(f='1.0/(1+1j*x)', xmin=-1, xmax=1, steps=200, p='x', g=None, erange=False, **kwargs):
    """
    Plots function(s) real and imaginary parts over the specified range.

    Parameters
    ----------
    f='1.0/(1+1j*x)'
        Complex-valued function or list of functions to plot.
        These can be string functions or single-argument python functions;
        additional globals can be supplied by g.
    xmin=-1, xmax=1, steps=200
        Range over which to plot and how many points to plot
    p='x'
        If using strings for functions, p is the independent parameter name.
    g=None
        Optional dictionary of extra globals. Try g=globals()!
    erange=False
        Use exponential spacing of the x data?

    See spinmob.plot.xy.data() for additional optional keyword arguments.
    """
    function(f, xmin, xmax, steps, p, g, erange, plotter=realimag_data, **kwargs)


Instruction:
Explain what the following Python 3 code does
def xy_data(xdata, ydata, eydata=None, exdata=None, label=None, xlabel='', ylabel='',               \
            title='', shell_history=0, xshift=0, yshift=0, xshift_every=1, yshift_every=1,        \
            coarsen=0, style=None,  clear=True, axes=None, xscale='linear', yscale='linear', grid=False,       \
            legend='best', legend_max=20, autoformat=True, autoformat_window=True, tall=False, draw=True, **kwargs):
    """
    Plots specified data.

    Parameters
    ----------
    xdata, ydata
        Arrays (or arrays of arrays) of data to plot
    eydata=None, exdata=None
        Arrays of x and y errorbar values
    label=None
        String or array of strings for the line labels
    xlabel=''
        Label for the x-axis
    ylabel=''
        Label for the y-axis
    title=''
        Title for the axes; set to None to have nothing.
    shell_history=0
        How many commands from the pyshell history to include with the title
    xshift=0, yshift=0
        Progressive shifts on the data, to make waterfall plots
    xshift_every=1
        Perform the progressive shift every 1 or n'th line.
    yshift_every=1
        perform the progressive shift every 1 or n'th line.
    style=None
        style cycle object.
    clear=True
        If no axes are specified (see below), clear the figure, otherwise clear just the axes.
    axes=None
        Which matplotlib axes to use, or "gca" for the current axes
    xscale='linear', yscale='linear'
        'linear' or 'log' x and y axis scales.
    grid=False
        Should we draw a grid on the axes?
    legend='best'
        Where to place the legend (see pylab.legend() for options)
        Set this to None to ignore the legend.
    legend_max=20
        Number of legend entries before it's truncated with '...'
    autoformat=True
        Should we format the figure for printing?
    autoformat_window=True
        Should we resize and reposition the window when autoformatting?
    tall=False
        Should the format be tall?
    draw=True
        Whether or not to draw the plot after plotting.

    See matplotlib's errorbar() function for additional optional keyword arguments.
    """
    _pylab.ioff()

    # Make sure the dimensionality of the data sets matches
    xdata, ydata = _match_data_sets(xdata, ydata)
    exdata = _match_error_to_data_set(xdata, exdata)
    eydata = _match_error_to_data_set(ydata, eydata)

    # check that the labels is a list of strings of the same length
    if not _fun.is_iterable(label): label = [label]*len(xdata)
    while len(label) < len(ydata):  label.append(label[0])

    # concatenate if necessary
    if len(label) > legend_max:
        label[legend_max-2] = '...'
        for n in range(legend_max-1,len(label)-1): label[n] = "_nolegend_"

    # clear the figure?
    if clear and not axes: _pylab.gcf().clear() # axes cleared later

    # setup axes
    if axes=="gca" or axes is None: axes = _pylab.gca()

    # if we're clearing the axes
    if clear: axes.clear()

    # set the current axes
    _pylab.axes(axes)

    # now loop over the list of data in xdata and ydata
    for n in range(0,len(xdata)):
        # get the label
        if label[n]=='_nolegend_':
            l = '_nolegend_'
        else:
            l = str(n)+": "+str(label[n])

        # calculate the x an y progressive shifts
        dx = xshift*(n/xshift_every)
        dy = yshift*(n/yshift_every)

        # if we're supposed to coarsen the data, do so.
        x  = _fun.coarsen_array(xdata[n],  coarsen)
        y  = _fun.coarsen_array(ydata[n],  coarsen)
        ey = _fun.coarsen_array(eydata[n], coarsen, 'quadrature')
        ex = _fun.coarsen_array(exdata[n], coarsen, 'quadrature')

        # update the style
        if not style is None: kwargs.update(next(style))
        axes.errorbar(x+dx, y+dy, label=l, yerr=ey, xerr=ex, **kwargs)

    _pylab.xscale(xscale)
    _pylab.yscale(yscale)
    if legend: axes.legend(loc=legend)
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)

    # for some arguments there should be no title.
    if title in [None, False, 0]:
        axes.set_title('')

    # add the commands to the title
    else:
        title = str(title)
        history = _fun.get_shell_history()
        for n in range(0, min(shell_history, len(history))):
            title = title + "\n" + history[n].split('\n')[0].strip()

        title = title + '\nPlot created ' + _time.asctime()
        axes.set_title(title)

    if grid: _pylab.grid(True)

    if autoformat:
        _pt.format_figure(draw=False, modify_geometry=autoformat_window)
        _pt.auto_zoom(axes=axes, draw=False)

    # update the canvas
    if draw:
        _pylab.ion()
        _pylab.draw()
        _pylab.show()

    return axes

Response: Plots the data of xdata ydata and eydata.


Instruction:
How would you implement a function in Python 3 that
generates and plot ydata versus xdata.

Response:
def xy_databoxes(ds, xscript=0, yscript='d[1]', eyscript=None, exscript=None, g=None, **kwargs):
    """
    Use databoxes and scripts to generate and plot ydata versus xdata.

    Parameters
    ----------
    ds
        List of databoxes
    xscript=0
        Script for x data
    yscript='d[1]'
        Script for y data
    eyscript=None
        Script for y error
    exscript=None
        Script for x error
    g=None
        Optional dictionary of globals for the scripts

    See spinmob.plot.xy.data() for additional optional keyword arguments.
    See spinmob.data.databox.execute_script() for more information about scripts.

    """
    databoxes(ds, xscript, yscript, eyscript, exscript, plotter=xy_data, g=g, **kwargs)


Instruction:
Explain what the following Python 3 code does
def xy_function(f='sin(x)', xmin=-1, xmax=1, steps=200, p='x', g=None, erange=False, **kwargs):
    function(f, xmin, xmax, steps, p, g, erange, plotter=xy_data, **kwargs)

Response: Plots a function over the specified range of points.


Instruction:
Explain what the following Python 3 code does
def databoxes(ds, xscript=0, yscript=1, eyscript=None, exscript=None, g=None, plotter=xy_data, transpose=False, **kwargs):
    if not _fun.is_iterable(ds): ds = [ds]

    if 'xlabel' not in kwargs: kwargs['xlabel'] = str(xscript)
    if 'ylabel' not in kwargs: kwargs['ylabel'] = str(yscript)

    # First make sure everything is a list of scripts (or None's)
    if not _fun.is_iterable(xscript): xscript = [xscript]
    if not _fun.is_iterable(yscript): yscript = [yscript]
    if not _fun.is_iterable(exscript): exscript = [exscript]
    if not _fun.is_iterable(eyscript): eyscript = [eyscript]

    # make sure exscript matches shape with xscript (and the same for y)
    if len(exscript)   < len(xscript):
        for n in range(len(xscript)-1): exscript.append(exscript[0])
    if len(eyscript)   < len(yscript):
        for n in range(len(yscript)-1): eyscript.append(eyscript[0])

    # Make xscript and exscript match in shape with yscript and eyscript
    if len(xscript)    < len(yscript):
        for n in range(len(yscript)-1):
            xscript.append(xscript[0])
            exscript.append(exscript[0])

    # check for the reverse possibility
    if len(yscript)    < len(xscript):
        for n in range(len(xscript)-1):
            yscript.append(yscript[0])
            eyscript.append(eyscript[0])

    # now check for None's (counting scripts)
    for n in range(len(xscript)):
        if xscript[n] is None and yscript[n] is None:
            print("Two None scripts? But why?")
            return
        if xscript[n] is None:
            if type(yscript[n])==str: xscript[n] = 'range(len('+yscript[n]+'))'
            else:                     xscript[n] = 'range(len(c('+str(yscript[n])+')))'
        if yscript[n] is None:
            if type(xscript[n])==str: yscript[n] = 'range(len('+xscript[n]+'))'
            else:                     yscript[n] = 'range(len(c('+str(xscript[n])+')))'

    xdatas  = []
    ydatas  = []
    exdatas = []
    eydatas = []
    labels  = []

    # Loop over all the data boxes
    for i in range(len(ds)):

        # Reset the default globals
        all_globals = dict(n=i,m=len(ds)-1-i)

        # Update them with the user-specified globals
        if not g==None: all_globals.update(g)

        # For ease of coding
        d = ds[i]

        # Take the transpose if necessary
        if transpose: d = d.transpose()

        # Generate the x-data; returns a list of outputs, one for each xscript
        xdata = d(xscript, all_globals)

        # Loop over each xdata, appending to the master list, and generating a label
        for n in range(len(xdata)):
            xdatas.append(xdata[n])
            if len(xdata)>1: labels.append(str(n)+": "+_os.path.split(d.path)[-1])
            else:            labels.append(_os.path.split(d.path)[-1])

        # Append the other data sets to their master lists
        for y in d( yscript, all_globals):  ydatas.append(y)
        for x in d(exscript, all_globals): exdatas.append(x)
        for y in d(eyscript, all_globals): eydatas.append(y)

    if "label" in kwargs: labels = kwargs.pop("label")

    plotter(xdatas, ydatas, eydatas, exdatas, label=labels, **kwargs)

Response: Returns a list of databoxes with the specified scripts.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def image_data(Z, X=[0,1.0], Y=[0,1.0], aspect=1.0, zmin=None, zmax=None, clear=1, clabel='z', autoformat=True, colormap="Last Used", shell_history=0, **kwargs):
    global _colormap

    # Set interpolation to something more relevant for every day science
    if not 'interpolation' in kwargs.keys(): kwargs['interpolation'] = 'nearest'

    _pylab.ioff()

    fig = _pylab.gcf()
    if clear:
        fig.clear()
        _pylab.axes()

    # generate the 3d axes
    X = _n.array(X)
    Y = _n.array(Y)
    Z = _n.array(Z)

    # assume X and Y are the bin centers and figure out the bin widths
    x_width = abs(float(X[-1] - X[0])/(len(Z[0])-1))
    y_width = abs(float(Y[-1] - Y[0])/(len(Z)-1))

    # reverse the Z's
    # Transpose and reverse
    Z = Z.transpose()
    Z = Z[-1::-1]

    # get rid of the label and title kwargs
    xlabel=''
    ylabel=''
    title =''
    if 'xlabel' in kwargs: xlabel = kwargs.pop('xlabel')
    if 'ylabel' in kwargs: ylabel = kwargs.pop('ylabel')
    if 'title' in kwargs:  title  = kwargs.pop('title')

    _pylab.imshow(Z, extent=[X[0]-x_width/2.0, X[-1]+x_width/2.0,
                             Y[0]-y_width/2.0, Y[-1]+y_width/2.0], **kwargs)
    cb = _pylab.colorbar()
    _pt.image_set_clim(zmin,zmax)
    _pt.image_set_aspect(aspect)
    cb.set_label(clabel)

    a = _pylab.gca()
    a.set_xlabel(xlabel)
    a.set_ylabel(ylabel)

    #_pt.close_sliders()
    #_pt.image_sliders()

    # title
    history = _fun.get_shell_history()
    for n in range(0, min(shell_history, len(history))):
        title = title + "\n" + history[n].split('\n')[0].strip()

    title = title + '\nPlot created ' + _time.asctime()
    a.set_title(title.strip())

    if autoformat: _pt.image_format_figure(fig)

    _pylab.ion()
    _pylab.show()
    #_pt.raise_figure_window()
    #_pt.raise_pyshell()
    _pylab.draw()

    # add the color sliders
    if colormap:
        if _colormap: _colormap.close()
        _colormap = _pt.image_colormap(colormap, image=a.images[0])

Response: Generates an image plot for the given data.


Instruction:
Create a Python 3 function for
generating a 2 - d function over the specified range and return one value.

Response:
def image_function(f='sin(5*x)*cos(5*y)', xmin=-1, xmax=1, ymin=-1, ymax=1, xsteps=100, ysteps=100, p='x,y', g=None, **kwargs):
    """
    Plots a 2-d function over the specified range

    Parameters
    ----------
    f='sin(5*x)*cos(5*y)'
        Takes two inputs and returns one value. Can also
        be a string function such as sin(x*y)
    xmin=-1, xmax=1, ymin=-1, ymax=1
        Range over which to generate/plot the data
    xsteps=100, ysteps=100
        How many points to plot on the specified range
    p='x,y'
        If using strings for functions, this is a string of parameters.
    g=None
        Optional additional globals. Try g=globals()!

    See spinmob.plot.image.data() for additional optional keyword arguments.
    """

    default_kwargs = dict(clabel=str(f), xlabel='x', ylabel='y')
    default_kwargs.update(kwargs)

    # aggregate globals
    if not g: g = {}
    for k in list(globals().keys()):
        if k not in g: g[k] = globals()[k]

    if type(f) == str:
        f = eval('lambda ' + p + ': ' + f, g)

    # generate the grid x and y coordinates
    xones = _n.linspace(1,1,ysteps)
    x     = _n.linspace(xmin, xmax, xsteps)
    xgrid = _n.outer(xones, x)

    yones = _n.linspace(1,1,xsteps)
    y     = _n.linspace(ymin, ymax, ysteps)
    ygrid = _n.outer(y, yones)

    # now get the z-grid
    try:
        # try it the fast numpy way. Add 0 to assure dimensions
        zgrid = f(xgrid, ygrid) + xgrid*0.0
    except:
        print("Notice: function is not rocking hardcore. Generating grid the slow way...")
        # manually loop over the data to generate the z-grid
        zgrid = []
        for ny in range(0, len(y)):
            zgrid.append([])
            for nx in range(0, len(x)):
                zgrid[ny].append(f(x[nx], y[ny]))

        zgrid = _n.array(zgrid)

    # now plot!
    image_data(zgrid.transpose(), x, y, **default_kwargs)


Instruction:
Implement a Python 3 function for
loading an image file and plot it with color.

Response:
def image_file(path=None, zscript='self[1:]', xscript='[0,1]', yscript='d[0]', g=None, **kwargs):
    """
    Loads an data file and plots it with color. Data file must have columns of the
    same length!

    Parameters
    ----------
    path=None
        Path to data file.
    zscript='self[1:]'
        Determines how to get data from the columns
    xscript='[0,1]', yscript='d[0]'
        Determine the x and y arrays used for setting the axes bounds
    g=None
        Optional dictionary of globals for the scripts

    See spinmob.plot.image.data() for additional optional keyword arguments.
    See spinmob.data.databox.execute_script() for more information about scripts.
    """
    if 'delimiter' in kwargs: delimiter = kwargs.pop('delimiter')
    else:                           delimiter = None

    d = _data.load(paths=path, delimiter = delimiter)
    if d is None or len(d) == 0: return

    # allows the user to overwrite the defaults
    default_kwargs = dict(xlabel = str(xscript),
                          ylabel = str(yscript),
                          title  = d.path,
                          clabel = str(zscript))
    default_kwargs.update(kwargs)

    # get the data
    X = d(xscript, g)
    Y = d(yscript, g)
    Z = _n.array(d(zscript, g))
#    Z = Z.transpose()

    # plot!
    image_data(Z, X, Y, **default_kwargs)


Instruction:
How would you code a function in Python 3 to
function that returns a parameterized version of the parametric function at a specified time range.

Response:
def parametric_function(fx='sin(t)', fy='cos(t)', tmin=-1, tmax=1, steps=200, p='t', g=None, erange=False, **kwargs):
    """
    Plots the parametric function over the specified range

    Parameters
    ----------
    fx='sin(t)', fy='cos(t)'
        Functions or (matching) lists of functions to plot;
        can be string functions or python functions taking one argument
    tmin=-1, tmax=1, steps=200
        Range over which to plot, and how many points to plot
    p='t'
        If using strings for functions, p is the parameter name
    g=None
        Optional dictionary of extra globals. Try g=globals()!
    erange=False
        Use exponential spacing of the t data?

    See spinmob.plot.xy.data() for additional optional keyword arguments.
    """

    if not g: g = {}
    for k in list(globals().keys()):
        if k not in g: g[k] = globals()[k]

    # if the x-axis is a log scale, use erange
    if erange: r = _fun.erange(tmin, tmax, steps)
    else:      r = _n.linspace(tmin, tmax, steps)

    # make sure it's a list so we can loop over it
    if not type(fy) in [type([]), type(())]: fy = [fy]
    if not type(fx) in [type([]), type(())]: fx = [fx]

    # loop over the list of functions
    xdatas = []
    ydatas = []
    labels = []
    for fs in fx:
        if type(fs) == str:
            a = eval('lambda ' + p + ': ' + fs, g)
            a.__name__ = fs
        else:
            a = fs

        x = []
        for z in r: x.append(a(z))

        xdatas.append(x)
        labels.append(a.__name__)

    for n in range(len(fy)):
        fs = fy[n]
        if type(fs) == str:
            a = eval('lambda ' + p + ': ' + fs, g)
            a.__name__ = fs
        else:
            a = fs

        y = []
        for z in r: y.append(a(z))

        ydatas.append(y)
        labels[n] = labels[n]+', '+a.__name__

    # plot!
    xy_data(xdatas, ydatas, label=labels, **kwargs)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def reset(self):
        for key in list(self.keys()): self.iterators[key] = _itertools.cycle(self[key])
        return self

Response: Reset the style cycle.


Instruction:
Create a Python 3 function for
adding text to the specified position.

Response:
def add_text(text, x=0.01, y=0.01, axes="gca", draw=True, **kwargs):
    """
    Adds text to the axes at the specified position.

    **kwargs go to the axes.text() function.
    """
    if axes=="gca": axes = _pylab.gca()
    axes.text(x, y, text, transform=axes.transAxes, **kwargs)
    if draw: _pylab.draw()


Instruction:
Can you write a function in Python 3 where it
looks at the bounds of the plotted data and zooms accordingly, leaving some space around the data.

Response:
def auto_zoom(zoomx=True, zoomy=True, axes="gca", x_space=0.04, y_space=0.04, draw=True):
    """
    Looks at the bounds of the plotted data and zooms accordingly, leaving some
    space around the data.
    """

    # Disable auto-updating by default.
    _pylab.ioff()

    if axes=="gca": axes = _pylab.gca()

    # get the current bounds
    x10, x20 = axes.get_xlim()
    y10, y20 = axes.get_ylim()

    # Autoscale using pylab's technique (catches the error bars!)
    axes.autoscale(enable=True, tight=True)

    # Add padding
    if axes.get_xscale() == 'linear':
        x1, x2 = axes.get_xlim()
        xc = 0.5*(x1+x2)
        xs = 0.5*(1+x_space)*(x2-x1)
        axes.set_xlim(xc-xs, xc+xs)

    if axes.get_yscale() == 'linear':
        y1, y2 = axes.get_ylim()
        yc = 0.5*(y1+y2)
        ys = 0.5*(1+y_space)*(y2-y1)
        axes.set_ylim(yc-ys, yc+ys)

    # If we weren't supposed to zoom x or y, reset them
    if not zoomx: axes.set_xlim(x10, x20)
    if not zoomy: axes.set_ylim(y10, y20)

    if draw:
        _pylab.ion()
        _pylab.draw()


Instruction:
Can you create a Python 3 function that
estimates the slope of two clicks.

Response:
def click_estimate_slope():
    """
    Takes two clicks and returns the slope.

    Right-click aborts.
    """

    c1 = _pylab.ginput()
    if len(c1)==0:
        return None

    c2 = _pylab.ginput()
    if len(c2)==0:
        return None

    return (c1[0][1]-c2[0][1])/(c1[0][0]-c2[0][0])


Instruction:
Can you tell what is the following Python 3 function doing
def click_estimate_curvature():

    c1 = _pylab.ginput()
    if len(c1)==0:
        return None

    c2 = _pylab.ginput()
    if len(c2)==0:
        return None

    return 2*(c2[0][1]-c1[0][1])/(c2[0][0]-c1[0][0])**2

Response: Takes two clicks and returns the curvature assuming the first click was the minimum of a parabola and the second was some other point. Right - click aborts.


Instruction:
Given the following Python 3 function, write the documentation
def click_estimate_difference():

    c1 = _pylab.ginput()
    if len(c1)==0:
        return None

    c2 = _pylab.ginput()
    if len(c2)==0:
        return None

    return [c2[0][0]-c1[0][0], c2[0][1]-c1[0][1]]

Response: Takes two clicks and returns the difference vector [ dx dy )


Instruction:
Can you generate the documentation for the following Python 3 function
def copy_figure_to_clipboard(figure='gcf'):
    try:
        import pyqtgraph as _p

        # Get the current figure if necessary
        if figure is 'gcf': figure = _s.pylab.gcf()

        # Store the figure as an image
        path = _os.path.join(_s.settings.path_home, "clipboard.png")
        figure.savefig(path)

        # Set the clipboard. I know, it's weird to use pyqtgraph, but
        # This covers both Qt4 and Qt5 with their Qt4 wrapper!
        _p.QtGui.QApplication.instance().clipboard().setImage(_p.QtGui.QImage(path))

    except:
        print("This function currently requires pyqtgraph to be installed.")

Response: Copies the specified figure to the system clipboard. Specifying gcf will use the current figure.


Instruction:
Write a Python 3 function for
differentiating the data visible on the specified axes using manipulate_shown_data.

Response:
def differentiate_shown_data(neighbors=1, fyname=1, **kwargs):
    """
    Differentiates the data visible on the specified axes using
    fun.derivative_fit() (if neighbors > 0), and derivative() otherwise.
    Modifies the visible data using manipulate_shown_data(**kwargs)
    """

    if neighbors:
        def D(x,y): return _fun.derivative_fit(x,y,neighbors)
    else:
        def D(x,y): return _fun.derivative(x,y)

    if fyname==1: fyname = '$\\partial_{x(\\pm'+str(neighbors)+')}$'

    manipulate_shown_data(D, fxname=None, fyname=fyname, **kwargs)


Instruction:
Here you have a function in Python 3, explain what it does
def fit_shown_data(f="a*x+b", p="a=1, b=2", axes="gca", verbose=True, **kwargs):

    # get the axes
    if axes=="gca": axes = _pylab.gca()

    # get the range for trimming
    _pylab.sca(axes)
    xmin,xmax = axes.get_xlim()
    ymin,ymax = axes.get_ylim()

    # update the kwargs
    if 'first_figure' not in kwargs: kwargs['first_figure'] = axes.figure.number+1

    # loop over the lines
    fitters = []
    for l in axes.lines:

        # get the trimmed data
        x,y = l.get_data()
        x,y = _s.fun.trim_data_uber([x,y],[xmin<x,x<xmax,ymin<y,y<ymax])

        # create a fitter
        fitters.append(_s.data.fitter(**kwargs).set_functions(f=f, p=p))
        fitters[-1].set_data(x,y)
        fitters[-1].fit()
        fitters[-1].autoscale_eydata().fit()
        if verbose:
            print(fitters[-1])
            print("<click the graph to continue>")
        if not axes.lines[-1] == l: fitters[-1].ginput(timeout=0)

    return fitters

Response: Fits the data of the specified function on the lines of the specified axes and returns a list of fitters that can be used to fit the data.


Instruction:
Write a Python 3 script for
formatting a figure in a compact way with enough useful useful information for large data sets.

Response:
def format_figure(figure=None, tall=False, draw=True, modify_geometry=True):
    """
    This formats the figure in a compact way with (hopefully) enough useful
    information for printing large data sets. Used mostly for line and scatter
    plots with long, information-filled titles.

    Chances are somewhat slim this will be ideal for you but it very well might
    and is at least a good starting point.

    figure=None     specify a figure object. None will use gcf()

    """
    _pylab.ioff()

    if figure == None: figure = _pylab.gcf()

    if modify_geometry:
        if tall: set_figure_window_geometry(figure, (0,0), (550,700))
        else:    set_figure_window_geometry(figure, (0,0), (550,400))

    legend_position=1.01

    # first, find overall bounds of all axes.
    ymin = 1.0
    ymax = 0.0
    xmin = 1.0
    xmax = 0.0
    for axes in figure.get_axes():
        (x,y,dx,dy) = axes.get_position().bounds
        if y    < ymin: ymin = y
        if y+dy > ymax: ymax = y+dy
        if x    < xmin: xmin = x
        if x+dx > xmax: xmax = x+dx

    # Fraction of the figure's width and height to use for all the plots.
    w = 0.55
    h = 0.75

    # buffers on left and bottom edges
    bb = 0.15
    bl = 0.15

    xscale = w / (xmax-xmin)
    yscale = h / (ymax-ymin)

    # save this for resetting
    current_axes = _pylab.gca()

    # loop over the axes
    for axes in figure.get_axes():

        # Get the axes bounds
        (x,y,dx,dy) = axes.get_position().bounds
        y  = bb + (y-ymin)*yscale
        dy = dy * yscale

        x  = bl + (x-xmin)*xscale
        dx = dx * xscale

        axes.set_position([x,y,dx,dy])

        # set the position of the legend
        _pylab.axes(axes) # set the current axes
        if len(axes.lines)>0:
            _pylab.legend(loc=[legend_position, 0], borderpad=0.02, prop=_FontProperties(size=7))

        # set the label spacing in the legend
        if axes.get_legend():
            axes.get_legend().labelsep = 0.01
            axes.get_legend().set_visible(1)

        # set up the title label
        axes.title.set_horizontalalignment('right')
        axes.title.set_size(8)
        axes.title.set_position([1.5,1.02])
        axes.title.set_visible(1)
        #axes.yaxis.label.set_horizontalalignment('center')
        #axes.xaxis.label.set_horizontalalignment('center')

    _pylab.axes(current_axes)

    if draw:
        _pylab.ion()
        _pylab.draw()


Instruction:
Given the following Python 3 function, write the documentation
def get_figure_window_geometry(fig='gcf'):

    if type(fig)==str:          fig = _pylab.gcf()
    elif _fun.is_a_number(fig): fig = _pylab.figure(fig)

    # Qt4Agg backend. Probably would work for other Qt stuff
    if _pylab.get_backend().find('Qt') >= 0:
        size = fig.canvas.window().size()
        pos  = fig.canvas.window().pos()
        return [[pos.x(),pos.y()], [size.width(),size.height()]]

    else:
        print("get_figure_window_geometry() only implemented for QtAgg backend.")
        return None

Response: Returns the geometry of the figure window.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def impose_legend_limit(limit=30, axes="gca", **kwargs):
    if axes=="gca": axes = _pylab.gca()

    # make these axes current
    _pylab.axes(axes)

    # loop over all the lines_pylab.
    for n in range(0,len(axes.lines)):
        if n >  limit-1 and not n==len(axes.lines)-1: axes.lines[n].set_label("_nolegend_")
        if n == limit-1 and not n==len(axes.lines)-1: axes.lines[n].set_label("...")

    _pylab.legend(**kwargs)

Response: Impose the legend to a maximum of 30 entries.


Instruction:
Explain what the following Python 3 code does
def image_neighbor_smooth(xlevel=0.2, ylevel=0.2, image="auto"):
    if image == "auto": image = _pylab.gca().images[0]

    Z = _n.array(image.get_array())

    # store this image in the undo list
    global image_undo_list
    image_undo_list.append([image, Z])
    if len(image_undo_list) > 10: image_undo_list.pop(0)

    # get the diagonal smoothing level (eliptical, and scaled down by distance)
    dlevel = ((xlevel**2+ylevel**2)/2.0)**(0.5)

    # don't touch the first column
    new_Z = [Z[0]*1.0]

    for m in range(1,len(Z)-1):
        new_Z.append(Z[m]*1.0)
        for n in range(1,len(Z[0])-1):
            new_Z[-1][n] = (Z[m,n] + xlevel*(Z[m+1,n]+Z[m-1,n]) + ylevel*(Z[m,n+1]+Z[m,n-1])   \
                                   + dlevel*(Z[m+1,n+1]+Z[m-1,n+1]+Z[m+1,n-1]+Z[m-1,n-1])   )  \
                                   / (1.0+xlevel*2+ylevel*2 + dlevel*4)

    # don't touch the last column
    new_Z.append(Z[-1]*1.0)

    # images have transposed data
    image.set_array(_n.array(new_Z))

    # update the plot
    _pylab.draw()

Response: This function will bleed nearest neighbor pixels into each other with the specified weight factors.


Instruction:
Make a summary of the following Python 3 code
def image_undo():
    if len(image_undo_list) <= 0:
        print("no undos in memory")
        return

    [image, Z] = image_undo_list.pop(-1)
    image.set_array(Z)
    _pylab.draw()

Response: Undoes the last coarsen or smooth command.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def image_set_aspect(aspect=1.0, axes="gca"):
    if axes is "gca": axes = _pylab.gca()

    e = axes.get_images()[0].get_extent()
    axes.set_aspect(abs((e[1]-e[0])/(e[3]-e[2]))/aspect)

Response: Sets the aspect ratio of the current zoom level of the imshow image


Instruction:
Given the following Python 3 function, write the documentation
def image_set_extent(x=None, y=None, axes="gca"):
    if axes == "gca": axes = _pylab.gca()

    # get the current plot limits
    xlim = axes.get_xlim()
    ylim = axes.get_ylim()

    # get the old extent
    extent = axes.images[0].get_extent()

    # calculate the fractional extents
    x0     = extent[0]
    y0     = extent[2]
    xwidth = extent[1]-x0
    ywidth = extent[3]-y0
    frac_x1 = (xlim[0]-x0)/xwidth
    frac_x2 = (xlim[1]-x0)/xwidth
    frac_y1 = (ylim[0]-y0)/ywidth
    frac_y2 = (ylim[1]-y0)/ywidth

    # set the new
    if not x == None:
        extent[0] = x[0]
        extent[1] = x[1]
    if not y == None:
        extent[2] = y[0]
        extent[3] = y[1]

    # get the new zoom window
    x0     = extent[0]
    y0     = extent[2]
    xwidth = extent[1]-x0
    ywidth = extent[3]-y0

    x1 = x0 + xwidth*frac_x1
    x2 = x0 + xwidth*frac_x2
    y1 = y0 + ywidth*frac_y1
    y2 = y0 + ywidth*frac_y2

    # set the extent
    axes.images[0].set_extent(extent)

    # rezoom us
    axes.set_xlim(x1,x2)
    axes.set_ylim(y1,y2)

    # draw
    image_set_aspect(1.0)

Response: Set the extent of the first image.


Instruction:
How would you explain what the following Python 3 function does
def image_scale(xscale=1.0, yscale=1.0, axes="gca"):
    if axes == "gca": axes = _pylab.gca()

    e = axes.images[0].get_extent()
    x1 = e[0]*xscale
    x2 = e[1]*xscale
    y1 = e[2]*yscale
    y2 = e[3]*yscale

    image_set_extent([x1,x2],[y1,y2], axes)

Response: Scales the image extent.


Instruction:
How would you code a function in Python 3 to
shift the image y by this amount

Response:
def image_click_xshift(axes = "gca"):
    """
    Takes a starting and ending point, then shifts the image y by this amount
    """
    if axes == "gca": axes = _pylab.gca()

    try:
        p1 = _pylab.ginput()
        p2 = _pylab.ginput()

        xshift = p2[0][0]-p1[0][0]

        e = axes.images[0].get_extent()

        e[0] = e[0] + xshift
        e[1] = e[1] + xshift

        axes.images[0].set_extent(e)

        _pylab.draw()
    except:
        print("whoops")


Instruction:
How would you code a function in Python 3 to
shift the image y by this amount

Response:
def image_click_yshift(axes = "gca"):
    """
    Takes a starting and ending point, then shifts the image y by this amount
    """
    if axes == "gca": axes = _pylab.gca()

    try:
        p1 = _pylab.ginput()
        p2 = _pylab.ginput()

        yshift = p2[0][1]-p1[0][1]

        e = axes.images[0].get_extent()

        e[2] = e[2] + yshift
        e[3] = e[3] + yshift

        axes.images[0].set_extent(e)

        _pylab.draw()
    except:
        print("whoops")


Instruction:
Given the following Python 3 function, write the documentation
def image_shift(xshift=0, yshift=0, axes="gca"):

    if axes=="gca": axes = _pylab.gca()

    e = axes.images[0].get_extent()

    e[0] = e[0] + xshift
    e[1] = e[1] + xshift
    e[2] = e[2] + yshift
    e[3] = e[3] + yshift

    axes.images[0].set_extent(e)

    _pylab.draw()

Response: This will shift an image to a new location on x and y.