1#=============================================================================== 2# Copyright (c) 2012-2015, GPy authors (see AUTHORS.txt). 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are met: 7# 8# * Redistributions of source code must retain the above copyright notice, this 9# list of conditions and the following disclaimer. 10# 11# * Redistributions in binary form must reproduce the above copyright notice, 12# this list of conditions and the following disclaimer in the documentation 13# and/or other materials provided with the distribution. 14# 15# * Neither the name of GPy nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29#=============================================================================== 30 31import numpy as np 32 33from . import plotting_library as pl 34from .plot_util import helper_for_plot_data, update_not_existing_kwargs, \ 35 helper_predict_with_model, get_which_data_ycols, get_x_y_var 36from .data_plots import _plot_data, _plot_inducing, _plot_data_error 37 38def plot_mean(self, plot_limits=None, fixed_inputs=None, 39 resolution=None, plot_raw=False, 40 apply_link=False, visible_dims=None, 41 which_data_ycols='all', 42 levels=20, projection='2d', 43 label='gp mean', 44 predict_kw=None, 45 **kwargs): 46 """ 47 Plot the mean of the GP. 48 49 You can deactivate the legend for this one plot by supplying None to label. 50 51 Give the Y_metadata in the predict_kw if you need it. 52 53 54 55 :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits 56 :type plot_limits: np.array 57 :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v. 58 :type fixed_inputs: a list of tuples 59 :param int resolution: The resolution of the prediction [defaults are 1D:200, 2D:50] 60 :param bool plot_raw: plot the latent function (usually denoted f) only? 61 :param bool apply_link: whether to apply the link function of the GP to the raw prediction. 62 :param array-like which_data_ycols: which columns of y to plot (array-like or list of ints) 63 :param int levels: for 2D plotting, the number of contour levels to use is 64 :param {'2d','3d'} projection: whether to plot in 2d or 3d. This only applies when plotting two dimensional inputs! 65 :param str label: the label for the plot. 66 :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 67 """ 68 canvas, kwargs = pl().new_canvas(projection=projection, **kwargs) 69 X = get_x_y_var(self)[0] 70 helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) 71 helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, 72 apply_link, None, 73 get_which_data_ycols(self, which_data_ycols), 74 predict_kw) 75 plots = _plot_mean(self, canvas, helper_data, helper_prediction, 76 levels, projection, label, **kwargs) 77 return pl().add_to_canvas(canvas, plots) 78 79def _plot_mean(self, canvas, helper_data, helper_prediction, 80 levels=20, projection='2d', label=None, 81 **kwargs): 82 83 _, free_dims, Xgrid, x, y, _, _, resolution = helper_data 84 if len(free_dims)<=2: 85 mu, _, _ = helper_prediction 86 if len(free_dims)==1: 87 # 1D plotting: 88 update_not_existing_kwargs(kwargs, pl().defaults.meanplot_1d) # @UndefinedVariable 89 plots = dict(gpmean=[pl().plot(canvas, Xgrid[:, free_dims], mu, label=label, **kwargs)]) 90 else: 91 if projection.lower() in '2d': 92 update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable 93 plots = dict(gpmean=[pl().contour(canvas, x[:,0], y[0,:], 94 mu.reshape(resolution, resolution).T, 95 levels=levels, label=label, **kwargs)]) 96 elif projection.lower() in '3d': 97 update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable 98 plots = dict(gpmean=[pl().surface(canvas, x, y, 99 mu.reshape(resolution, resolution), 100 label=label, 101 **kwargs)]) 102 elif len(free_dims)==0: 103 pass # Nothing to plot! 104 else: 105 raise RuntimeError('Cannot plot mean in more then 2 input dimensions') 106 return plots 107 108def plot_confidence(self, lower=2.5, upper=97.5, plot_limits=None, fixed_inputs=None, 109 resolution=None, plot_raw=False, 110 apply_link=False, visible_dims=None, 111 which_data_ycols='all', label='gp confidence', 112 predict_kw=None, 113 **kwargs): 114 """ 115 Plot the confidence interval between the percentiles lower and upper. 116 E.g. the 95% confidence interval is $2.5, 97.5$. 117 Note: Only implemented for one dimension! 118 119 You can deactivate the legend for this one plot by supplying None to label. 120 121 Give the Y_metadata in the predict_kw if you need it. 122 123 124 :param float lower: the lower percentile to plot 125 :param float upper: the upper percentile to plot 126 :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits 127 :type plot_limits: np.array 128 :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v. 129 :type fixed_inputs: a list of tuples 130 :param int resolution: The resolution of the prediction [default:200] 131 :param bool plot_raw: plot the latent function (usually denoted f) only? 132 :param bool apply_link: whether to apply the link function of the GP to the raw prediction. 133 :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) 134 :param array-like which_data_ycols: which columns of the output y (!) to plot (array-like or list of ints) 135 :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 136 """ 137 canvas, kwargs = pl().new_canvas(**kwargs) 138 ycols = get_which_data_ycols(self, which_data_ycols) 139 X = get_x_y_var(self)[0] 140 helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) 141 helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, apply_link, 142 (lower, upper), 143 ycols, predict_kw) 144 plots = _plot_confidence(self, canvas, helper_data, helper_prediction, label, **kwargs) 145 return pl().add_to_canvas(canvas, plots, legend=label is not None) 146 147def _plot_confidence(self, canvas, helper_data, helper_prediction, label, **kwargs): 148 _, free_dims, Xgrid, _, _, _, _, _ = helper_data 149 update_not_existing_kwargs(kwargs, pl().defaults.confidence_interval) # @UndefinedVariable 150 if len(free_dims)<=1: 151 if len(free_dims)==1: 152 percs = helper_prediction[1] 153 fills = [] 154 for d in range(helper_prediction[0].shape[1]): 155 fills.append(pl().fill_between(canvas, Xgrid[:,free_dims[0]], percs[0][:,d], percs[1][:,d], label=label, **kwargs)) 156 return dict(gpconfidence=fills) 157 else: 158 pass #Nothing to plot! 159 else: 160 raise RuntimeError('Can only plot confidence interval in one input dimension') 161 162 163def plot_samples(self, plot_limits=None, fixed_inputs=None, 164 resolution=None, plot_raw=True, 165 apply_link=False, visible_dims=None, 166 which_data_ycols='all', 167 samples=3, projection='2d', label='gp_samples', 168 predict_kw=None, 169 **kwargs): 170 """ 171 Plot the mean of the GP. 172 173 You can deactivate the legend for this one plot by supplying None to label. 174 175 Give the Y_metadata in the predict_kw if you need it. 176 177 178 179 :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits 180 :type plot_limits: np.array 181 :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v. 182 :type fixed_inputs: a list of tuples 183 :param int resolution: The resolution of the prediction [defaults are 1D:200, 2D:50] 184 :param bool plot_raw: plot the latent function (usually denoted f) only? This is usually what you want! 185 :param bool apply_link: whether to apply the link function of the GP to the raw prediction. 186 :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) 187 :param array-like which_data_ycols: which columns of y to plot (array-like or list of ints) 188 :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 189 :param int levels: for 2D plotting, the number of contour levels to use is 190 """ 191 canvas, kwargs = pl().new_canvas(projection=projection, **kwargs) 192 ycols = get_which_data_ycols(self, which_data_ycols) 193 X = get_x_y_var(self)[0] 194 helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) 195 helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, apply_link, 196 None, 197 ycols, predict_kw, samples) 198 plots = _plot_samples(self, canvas, helper_data, helper_prediction, 199 projection, label, **kwargs) 200 return pl().add_to_canvas(canvas, plots) 201 202def _plot_samples(self, canvas, helper_data, helper_prediction, projection, 203 label, **kwargs): 204 _, free_dims, Xgrid, x, y, _, _, resolution = helper_data 205 samples = helper_prediction[2] 206 207 if len(free_dims)<=2: 208 if len(free_dims)==1: 209 # 1D plotting: 210 update_not_existing_kwargs(kwargs, pl().defaults.samples_1d) # @UndefinedVariable 211 plots = [pl().plot(canvas, Xgrid[:, free_dims], samples[:, :, s], label=label if s==0 else None, **kwargs) for s in range(samples.shape[-1])] 212 elif len(free_dims)==2 and projection=='3d': 213 update_not_existing_kwargs(kwargs, pl().defaults.samples_3d) # @UndefinedVariable 214 plots = [pl().surface(canvas, x, y, samples[:, :, s].reshape(resolution, resolution), **kwargs) for s in range(samples.shape[-1])] 215 else: 216 pass # Nothing to plot! 217 return dict(gpmean=plots) 218 else: 219 raise RuntimeError('Cannot plot mean in more then 1 input dimensions') 220 221 222def plot_density(self, plot_limits=None, fixed_inputs=None, 223 resolution=None, plot_raw=False, 224 apply_link=False, visible_dims=None, 225 which_data_ycols='all', 226 levels=35, label='gp density', 227 predict_kw=None, 228 **kwargs): 229 """ 230 Plot the confidence interval between the percentiles lower and upper. 231 E.g. the 95% confidence interval is $2.5, 97.5$. 232 Note: Only implemented for one dimension! 233 234 You can deactivate the legend for this one plot by supplying None to label. 235 236 Give the Y_metadata in the predict_kw if you need it. 237 238 :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits 239 :type plot_limits: np.array 240 :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v. 241 :type fixed_inputs: a list of tuples 242 :param int resolution: The resolution of the prediction [default:200] 243 :param bool plot_raw: plot the latent function (usually denoted f) only? 244 :param bool apply_link: whether to apply the link function of the GP to the raw prediction. 245 :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) 246 :param array-like which_data_ycols: which columns of y to plot (array-like or list of ints) 247 :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. 248 :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 249 """ 250 canvas, kwargs = pl().new_canvas(**kwargs) 251 X = get_x_y_var(self)[0] 252 helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) 253 helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, 254 apply_link, np.linspace(2.5, 97.5, levels*2), 255 get_which_data_ycols(self, which_data_ycols), 256 predict_kw) 257 plots = _plot_density(self, canvas, helper_data, helper_prediction, label, **kwargs) 258 return pl().add_to_canvas(canvas, plots) 259 260def _plot_density(self, canvas, helper_data, helper_prediction, label, **kwargs): 261 _, free_dims, Xgrid, _, _, _, _, _ = helper_data 262 mu, percs, _ = helper_prediction 263 264 update_not_existing_kwargs(kwargs, pl().defaults.density) # @UndefinedVariable 265 266 if len(free_dims)<=1: 267 if len(free_dims)==1: 268 # 1D plotting: 269 fills = [] 270 for d in range(mu.shape[1]): 271 fills.append(pl().fill_gradient( 272 canvas, Xgrid[:, free_dims[0]], [p[:,d] for p in percs], 273 label=label, **kwargs) 274 ) 275 return dict(gpdensity=fills) 276 else: 277 pass # Nothing to plot! 278 else: 279 raise RuntimeError('Can only plot density in one input dimension') 280 281def plot(self, plot_limits=None, fixed_inputs=None, 282 resolution=None, 283 plot_raw=False, apply_link=False, 284 which_data_ycols='all', which_data_rows='all', 285 visible_dims=None, 286 levels=20, samples=0, samples_likelihood=0, lower=2.5, upper=97.5, 287 plot_data=True, plot_inducing=True, plot_density=False, 288 predict_kw=None, projection='2d', legend=True, **kwargs): 289 """ 290 Convenience function for plotting the fit of a GP. 291 292 You can deactivate the legend for this one plot by supplying None to label. 293 294 Give the Y_metadata in the predict_kw if you need it. 295 296 297 If you want fine graned control use the specific plotting functions supplied in the model. 298 299 :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits 300 :type plot_limits: np.array 301 :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v. 302 :type fixed_inputs: a list of tuples 303 :param int resolution: The resolution of the prediction [default:200] 304 :param bool plot_raw: plot the latent function (usually denoted f) only? 305 :param bool apply_link: whether to apply the link function of the GP to the raw prediction. 306 :param which_data_ycols: when the data has several columns (independant outputs), only plot these 307 :type which_data_ycols: 'all' or a list of integers 308 :param which_data_rows: which of the training data to plot (default all) 309 :type which_data_rows: 'all' or a slice object to slice self.X, self.Y 310 :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) 311 :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. 312 :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. 313 :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! 314 :param float lower: the lower percentile to plot 315 :param float upper: the upper percentile to plot 316 :param bool plot_data: plot the data into the plot? 317 :param bool plot_inducing: plot inducing inputs? 318 :param bool plot_density: plot density instead of the confidence interval? 319 :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 320 :param {2d|3d} projection: plot in 2d or 3d? 321 :param bool legend: convenience, whether to put a legend on the plot or not. 322 """ 323 X = get_x_y_var(self)[0] 324 helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) 325 xmin, xmax = helper_data[5:7] 326 free_dims = helper_data[1] 327 328 if not 'xlim' in kwargs: 329 kwargs['xlim'] = (xmin[0], xmax[0]) 330 if not 'ylim' in kwargs and len(free_dims) == 2: 331 kwargs['ylim'] = (xmin[1], xmax[1]) 332 333 canvas, _ = pl().new_canvas(projection=projection, **kwargs) 334 helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, 335 apply_link, np.linspace(2.5, 97.5, levels*2) if plot_density else (lower,upper), 336 get_which_data_ycols(self, which_data_ycols), 337 predict_kw, samples) 338 if plot_raw and not apply_link: 339 # It does not make sense to plot the data (which lives not in the latent function space) into latent function space. 340 plot_data = False 341 plots = {} 342 if hasattr(self, 'Z') and plot_inducing: 343 plots.update(_plot_inducing(self, canvas, free_dims, projection, 'Inducing')) 344 if plot_data: 345 plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, free_dims, projection, "Data")) 346 plots.update(_plot_data_error(self, canvas, which_data_rows, which_data_ycols, free_dims, projection, "Data Error")) 347 plots.update(_plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing, plot_density, projection)) 348 if plot_raw and (samples_likelihood > 0): 349 helper_prediction = helper_predict_with_model(self, helper_data[2], False, 350 apply_link, None, 351 get_which_data_ycols(self, which_data_ycols), 352 predict_kw, samples_likelihood) 353 plots.update(_plot_samples(canvas, helper_data, helper_prediction, projection, "Lik Samples")) 354 return pl().add_to_canvas(canvas, plots, legend=legend) 355 356 357def plot_f(self, plot_limits=None, fixed_inputs=None, 358 resolution=None, 359 apply_link=False, 360 which_data_ycols='all', which_data_rows='all', 361 visible_dims=None, 362 levels=20, samples=0, lower=2.5, upper=97.5, 363 plot_density=False, 364 plot_data=True, plot_inducing=True, 365 projection='2d', legend=True, 366 predict_kw=None, 367 **kwargs): 368 """ 369 Convinience function for plotting the fit of a GP. 370 This is the same as plot, except it plots the latent function fit of the GP! 371 372 If you want fine graned control use the specific plotting functions supplied in the model. 373 374 You can deactivate the legend for this one plot by supplying None to label. 375 376 Give the Y_metadata in the predict_kw if you need it. 377 378 379 :param plot_limits: The limits of the plot. If 1D [xmin,xmax], if 2D [[xmin,ymin],[xmax,ymax]]. Defaluts to data limits 380 :type plot_limits: np.array 381 :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input dimension i should be set to value v. 382 :type fixed_inputs: a list of tuples 383 :param int resolution: The resolution of the prediction [default:200] 384 :param bool apply_link: whether to apply the link function of the GP to the raw prediction. 385 :param which_data_ycols: when the data has several columns (independant outputs), only plot these 386 :type which_data_ycols: 'all' or a list of integers 387 :param which_data_rows: which of the training data to plot (default all) 388 :type which_data_rows: 'all' or a slice object to slice self.X, self.Y 389 :param array-like visible_dims: an array specifying the input dimensions to plot (maximum two) 390 :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. 391 :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. 392 :param float lower: the lower percentile to plot 393 :param float upper: the upper percentile to plot 394 :param bool plot_data: plot the data into the plot? 395 :param bool plot_inducing: plot inducing inputs? 396 :param bool plot_density: plot density instead of the confidence interval? 397 :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 398 :param dict error_kwargs: kwargs for the error plot for the plotting library you are using 399 :param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using 400 """ 401 return plot(self, plot_limits, fixed_inputs, resolution, True, 402 apply_link, which_data_ycols, which_data_rows, 403 visible_dims, levels, samples, 0, 404 lower, upper, plot_data, plot_inducing, 405 plot_density, predict_kw, projection, legend, **kwargs) 406 407 408 409def _plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing=True, plot_density=False, projection='2d'): 410 plots.update(_plot_mean(self, canvas, helper_data, helper_prediction, levels, projection, 'Mean')) 411 412 try: 413 if projection=='2d': 414 if not plot_density: 415 plots.update(_plot_confidence(self, canvas, helper_data, helper_prediction, "Confidence")) 416 else: 417 plots.update(_plot_density(self, canvas, helper_data, helper_prediction, "Density")) 418 except RuntimeError: 419 #plotting in 2d 420 pass 421 422 if helper_prediction[2] is not None: 423 plots.update(_plot_samples(self, canvas, helper_data, helper_prediction, projection, "Samples")) 424 return plots 425