Convenience function for plotting the fit of a GP.

    You can deactivate the legend for this one plot by supplying None to label.

    Give the Y_metadata in the predict_kw if you need it.


    If you want fine graned control use the specific plotting functions supplied in the model.

    :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits
    :type plot_limits: np.array
    :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v.
    :type fixed_inputs: a list of tuples
    :param int resolution: The resolution of the prediction [default:200]
    :param bool plot_raw: plot the latent function (usually denoted f) only?
    :param bool apply_link: whether to apply the link function of the GP to the raw prediction.
    :param which_data_ycols: when the data has several columns (independant outputs), only plot these
    :type which_data_ycols: 'all' or a list of integers
    :param which_data_rows: which of the training data to plot (default all)
    :type which_data_rows: 'all' or a slice object to slice self.X, self.Y
    :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints)
    :param int levels: the number of levels in the density (number bigger then 1, where 35 is smooth and 1 is the same as plot_confidence). You can go higher then 50 if the result is not smooth enough for you.
    :param int samples: the number of samples to draw from the GP and plot into the plot. This will allways be samples from the latent function.
    :param int samples_likelihood: the number of samples to draw from the GP and apply the likelihood noise. This is usually not what you want!
    :param float lower: the lower percentile to plot
    :param float upper: the upper percentile to plot
    :param bool plot_data: plot the data into the plot?
    :param bool plot_inducing: plot inducing inputs?
    :param bool plot_density: plot density instead of the confidence interval?
    :param dict predict_kw: the keyword arguments for the prediction. If you want to plot a specific kernel give dict(kern=<specific kernel>) in here
    :param {2d|3d} projection: plot in 2d or 3d?
    :param bool legend: convenience, whether to put a legend on the plot or not.

def plot(self, plot_limits=None, fixed_inputs=None,
              resolution=None,
              plot_raw=False, apply_link=False,
              which_data_ycols='all', which_data_rows='all',
              visible_dims=None,
              levels=20, samples=0, samples_likelihood=0, lower=2.5, upper=97.5,
              plot_data=True, plot_inducing=True, plot_density=False,
              predict_kw=None, projection='2d', legend=True, **kwargs):
    """
    Convenience function for plotting the fit of a GP.

    You can deactivate the legend for this one plot by supplying None to label.

    Give the Y_metadata in the predict_kw if you need it.


    If you want fine graned control use the specific plotting functions supplied in the model.

    :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits
    :type plot_limits: np.array
    :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v.
    :type fixed_inputs: a list of tuples
    :param int resolution: The resolution of the prediction [default:200]
    :param bool plot_raw: plot the latent function (usually denoted f) only?
    :param bool apply_link: whether to apply the link function of the GP to the raw prediction.
    :param which_data_ycols: when the data has several columns (independant outputs), only plot these
    :type which_data_ycols: 'all' or a list of integers
    :param which_data_rows: which of the training data to plot (default all)
    :type which_data_rows: 'all' or a slice object to slice self.X, self.Y
    :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints)
    :param int levels: the number of levels in the density (number bigger then 1, where 35 is smooth and 1 is the same as plot_confidence). You can go higher then 50 if the result is not smooth enough for you.
    :param int samples: the number of samples to draw from the GP and plot into the plot. This will allways be samples from the latent function.
    :param int samples_likelihood: the number of samples to draw from the GP and apply the likelihood noise. This is usually not what you want!
    :param float lower: the lower percentile to plot
    :param float upper: the upper percentile to plot
    :param bool plot_data: plot the data into the plot?
    :param bool plot_inducing: plot inducing inputs?
    :param bool plot_density: plot density instead of the confidence interval?
    :param dict predict_kw: the keyword arguments for the prediction. If you want to plot a specific kernel give dict(kern=<specific kernel>) in here
    :param {2d|3d} projection: plot in 2d or 3d?
    :param bool legend: convenience, whether to put a legend on the plot or not.
    """
    X = get_x_y_var(self)[0]
    helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution)
    xmin, xmax = helper_data[5:7]
    free_dims = helper_data[1]

    if not 'xlim' in kwargs:
        kwargs['xlim'] = (xmin[0], xmax[0])
    if not 'ylim' in kwargs and len(free_dims) == 2:
        kwargs['ylim'] = (xmin[1], xmax[1])

    canvas, _ = pl().new_canvas(projection=projection, **kwargs)
    helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw,
                                          apply_link, np.linspace(2.5, 97.5, levels*2) if plot_density else (lower,upper),
                                          get_which_data_ycols(self, which_data_ycols),
                                          predict_kw, samples)
    if plot_raw and not apply_link:
        # It does not make sense to plot the data (which lives not in the latent function space) into latent function space.
        plot_data = False
    plots = {}
    if hasattr(self, 'Z') and plot_inducing:
        plots.update(_plot_inducing(self, canvas, free_dims, projection, 'Inducing'))
    if plot_data:
        plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, free_dims, projection, "Data"))
        plots.update(_plot_data_error(self, canvas, which_data_rows, which_data_ycols, free_dims, projection, "Data Error"))
    plots.update(_plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing, plot_density, projection))
    if plot_raw and (samples_likelihood > 0):
        helper_prediction = helper_predict_with_model(self, helper_data[2], False,
                                      apply_link, None,
                                      get_which_data_ycols(self, which_data_ycols),
                                      predict_kw, samples_likelihood)
        plots.update(_plot_samples(canvas, helper_data, helper_prediction, projection, "Lik Samples"))
    return pl().add_to_canvas(canvas, plots, legend=legend)