To determine the global helical axis by smoothing local axis using spline interpolation.

        .. note::
            A 3D curve is fitted on local helical axis that are calculated using
            ``do_x3dna`` tool. Sometimes in few frames, fitting **may not** be
            accurate and produces artifact. To record these frames, ``DNA.mask``
            array containing boolean values are generated. If value is ``True``,
            fitting might not be correct and vice versa. This array could be
            used in later analysis to skip/mask the frames containing inaccurate
            axis.

        .. warning::
                This function requires `SciPy package <http://www.scipy.org/>`_.

        Parameters
        ----------
        step_range : bool
            * ``step_range = True`` : Make axis smooth for the given range of base-steps
            * ``step_range = False``: Make axis smooth for for entire DNA. If original helical-axis of any base-step
                will be found to be not available, error will be raised.

        step : list
            List containing lower and higher limit of base-steps range.
                * This option only works with ``step_range=True``.
                * This list should not contain more than two number.
                * First number should be less than second number.

            Example for base-step 4 to 15:
                ``step = [4,15]         # step_range = True``

        smooth : float
            A smoothing condition. For more details, see about ``s = None``, which is passed into
            `scipy.interpolate.splprep() <https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.interpolate.splprep.html>`_ method.

            .. warning ::
                * Lower value may lead to an artifact of local sharp kink in the smoothed axis.
                * Higher value may lead to the calculation of wrong helical axis.

        spline : int
            Degree of spline. For more details, see about ``k = 3``, which is passed into
            `scipy.interpolate.splprep() <https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.interpolate.splprep.html>`_ method.

        fill_point : int
            Number of intrapolated points between two adjacent helical-axis coordinates.

        cut_off_angle : float
            Cut-off bending angle to define sharp kink in fitted curve. If angle
            in fitted curve is larger than this cut-off, refitting will be performed
            after deleting few of the original helical axis positions. If after
            this deletions, bending angle will not reduce below cut-off angle,
            value of ``smooth`` will be increased by 100 and entire cycle of
            fitting-refitting will be performed. When, value of ``smooth`` increases
            to more than 10000 during this fitting-refitting cycles, fitting process
            will be stopped with a warning message.

            To record the frames with bad fitting, ``True`` value will be
            stored in ``DNA.mask`` array for respective frame.

def generate_smooth_axis(self, step_range=False, step=None, smooth=500.0, spline=3, fill_point=6, cut_off_angle=20):
        """To determine the global helical axis by smoothing local axis using spline interpolation.

        .. note::
            A 3D curve is fitted on local helical axis that are calculated using
            ``do_x3dna`` tool. Sometimes in few frames, fitting **may not** be
            accurate and produces artifact. To record these frames, ``DNA.mask``
            array containing boolean values are generated. If value is ``True``,
            fitting might not be correct and vice versa. This array could be
            used in later analysis to skip/mask the frames containing inaccurate
            axis.

        .. warning::
                This function requires `SciPy package <http://www.scipy.org/>`_.

        Parameters
        ----------
        step_range : bool
            * ``step_range = True`` : Make axis smooth for the given range of base-steps
            * ``step_range = False``: Make axis smooth for for entire DNA. If original helical-axis of any base-step
                will be found to be not available, error will be raised.

        step : list
            List containing lower and higher limit of base-steps range.
                * This option only works with ``step_range=True``.
                * This list should not contain more than two number.
                * First number should be less than second number.

            Example for base-step 4 to 15:
                ``step = [4,15]         # step_range = True``

        smooth : float
            A smoothing condition. For more details, see about ``s = None``, which is passed into
            `scipy.interpolate.splprep() <https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.interpolate.splprep.html>`_ method.

            .. warning ::
                * Lower value may lead to an artifact of local sharp kink in the smoothed axis.
                * Higher value may lead to the calculation of wrong helical axis.

        spline : int
            Degree of spline. For more details, see about ``k = 3``, which is passed into
            `scipy.interpolate.splprep() <https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.interpolate.splprep.html>`_ method.

        fill_point : int
            Number of intrapolated points between two adjacent helical-axis coordinates.

        cut_off_angle : float
            Cut-off bending angle to define sharp kink in fitted curve. If angle
            in fitted curve is larger than this cut-off, refitting will be performed
            after deleting few of the original helical axis positions. If after
            this deletions, bending angle will not reduce below cut-off angle,
            value of ``smooth`` will be increased by 100 and entire cycle of
            fitting-refitting will be performed. When, value of ``smooth`` increases
            to more than 10000 during this fitting-refitting cycles, fitting process
            will be stopped with a warning message.

            To record the frames with bad fitting, ``True`` value will be
            stored in ``DNA.mask`` array for respective frame.

        """

        if not scipy_imported:
            raise ImportError(
                "SciPy package is not available. Please visit http://www.scipy.org/install.html for download and installation instructions.\n")

        if (step_range) and (step == None):
            raise ValueError(
                "See, documentation for step  and step_range usage!!!")

        bp_idx = []

        if step_range:
            if (len(step) != 2):
                raise ValueError("See, documentation for step usage!!!")

            if step[0] > step[1]:
                raise ValueError("See, documentation for step usage!!!")
            RawX, bp_idx = self.get_parameters( 'helical x-axis', step, bp_range=True)
            RawY, dummy = self.get_parameters( 'helical y-axis', step, bp_range=True)
            RawZ, dummy = self.get_parameters( 'helical z-axis', step, bp_range=True)
        else:
            RawX, bp_idx = self.get_parameters( 'helical x-axis', [1, self.num_step], bp_range=True)
            RawY, dummy = self.get_parameters( 'helical y-axis', [1, self.num_step], bp_range=True)
            RawZ, dummy = self.get_parameters( 'helical z-axis', [1, self.num_step], bp_range=True)

        RawX = np.array(RawX).T
        RawY = np.array(RawY).T
        RawZ = np.array(RawZ).T

        smoothX, smoothY, smoothZ = [], [], []

        nframes = len(self.time)

        maskArray = np.zeros(nframes, dtype=bool)

        for i in range(nframes):

            frame_number = i + 1
            if((frame_number < 100) and (frame_number % 10 == 0)) or ((frame_number < 1000) and (frame_number % 100 == 0)) or (frame_number % 1000 == 0):
                sys.stdout.write("\rFitting spline curve on helical axis of frame %d out of %d frames" % (
                    frame_number, nframes))
                sys.stdout.flush()

            xsmooth, ysmooth, zsmooth, mask = fit_axis(bp_idx, frame_number, RawX[i], RawY[i], RawZ[i], smooth, spline, fill_point, cut_off_angle)
            maskArray[i] = mask

            smoothX.append(xsmooth)
            smoothY.append(ysmooth)
            smoothZ.append(zsmooth)

        sys.stdout.write("\nFinished spline curve fitting...\n")
        sys.stdout.flush()

        smoothX = np.asarray(smoothX).T
        smoothY = np.asarray(smoothY).T
        smoothZ = np.asarray(smoothZ).T

        self.smooth_axis = True
        for i in range(len(bp_idx)):
            bp_num = str( bp_idx[i]+self.startBP )
            self._set_data(smoothX[i], 'bps', bp_num, 'helical x-axis smooth', scaleoffset=2)
            self._set_data(smoothY[i], 'bps', bp_num, 'helical y-axis smooth', scaleoffset=2)
            self._set_data(smoothZ[i], 'bps', bp_num, 'helical z-axis smooth', scaleoffset=2)

        # Set mask array
        self._set_mask(maskArray)