diff --git a/.travis.yml b/.travis.yml index 42e5815a..f470f05c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,17 @@ sudo: false os: - - osx - - linux +- osx +- linux -#language: python +addons: + apt_packages: + - pandoc -#addons: -# apt: -# packages: -# - gfortran -# - libatlas-dev -# - libatlas-base-dev -# - liblapack-dev - -cache: - directories: - - $HOME/download/ - - $HOME/install/ +#cache: +# directories: +# - "$HOME/download/" +# - "$HOME/install/" env: - PYTHON_VERSION=2.7 @@ -25,41 +19,54 @@ env: before_install: - export CONDA_CACHED=1 - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - export OS=Linux; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - export OS=MacOSX; - else - echo "OS not supported yet"; - exit 1; - fi; - - if [[ $PYTHON_VERSION == "2.7" ]]; then - export MINICONDA=Miniconda; - elif [[ $PYTHON_VERSION == 3* ]]; then - export MINICONDA=Miniconda3; - else - echo "Could not find python version"; - exit 1; - fi; + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then export OS=Linux; + elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; + then export OS=MacOSX; + brew install pandoc; + else + echo "OS not supported yet"; + exit 1; fi; + - if [[ $PYTHON_VERSION == "2.7" ]]; + then export MINICONDA=Miniconda; + elif [[ $PYTHON_VERSION == 3* ]]; + then export MINICONDA=Miniconda3; + else echo "Could not find python version";exit 1; fi; - if [ ! -d $HOME/download/ ]; then mkdir $HOME/download/; fi; - if [ ! -d $HOME/install/ ]; then mkdir $HOME/install/; fi; - export MINICONDA_FILE=$MINICONDA-latest-$OS-x86_64-$PYTHON_VERSION - export MINCONDA_CACHE_FILE=$HOME/download/$MINICONDA_FILE.sh - export MINICONDA_INSTALL=$HOME/install/$MINICONDA_FILE - - if [ ! -f $MINCONDA_CACHE_FILE ]; then - export CONDA_CACHED=0; - wget http://repo.continuum.io/miniconda/$MINICONDA-latest-$OS-x86_64.sh -O $MINCONDA_CACHE_FILE; - bash $MINCONDA_CACHE_FILE -b -p $MINICONDA_INSTALL; - fi; + - if [ ! -f $MINCONDA_CACHE_FILE ]; then export CONDA_CACHED=0; wget http://repo.continuum.io/miniconda/$MINICONDA-latest-$OS-x86_64.sh -O $MINCONDA_CACHE_FILE; bash $MINCONDA_CACHE_FILE -b -p $MINICONDA_INSTALL; fi; - export PATH="$MINICONDA_INSTALL/bin:$PATH"; - + install: - - conda install --yes python=$PYTHON_VERSION numpy=1.9 scipy=0.16 nose pip six matplotlib; + - conda install --yes python=$PYTHON_VERSION numpy=1.9 scipy=0.16 nose pip six matplotlib sphinx; - pip install codecov + - pip install pypandoc - python setup.py develop - + script: - coverage run travis_tests.py after_success: - - codecov \ No newline at end of file + - codecov + +before_deploy: + - cd doc + - pip install sphinx_rtd_theme + - sphinx-apidoc -o source/ ../GPy + - make html + - cd ../ + +deploy: + provider: pypi + user: maxz + password: + secure: "vMEOlP7DQhFJ7hQAKtKC5hrJXFl5BkUt4nXdosWWiw//Kg8E+PPLg88XPI2gqIosir9wwgtbSBBbbwCxkM6uxRNMpoNR8Ixyv9fmSXp4rLl7bbBY768W7IRXKIBjpuEy2brQjoT+CwDDSzUkckHvuUjJDNRvUv8ab4P/qYO1LG4=" + on: + #tags: true + branch: plot_density + server: https://testpypi.python.org/pypi + distributions: "bdist_wheel sdist" + skip_cleanup: true diff --git a/AUTHORS.txt b/AUTHORS.txt index a446ebb4..08ee8401 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -1 +1 @@ -See contributors. +[GPy Authors](https://github.com/SheffieldML/GPy/graphs/contributors) \ No newline at end of file diff --git a/GPy/__init__.py b/GPy/__init__.py index 170f7e10..32f0c1c4 100644 --- a/GPy/__init__.py +++ b/GPy/__init__.py @@ -49,7 +49,7 @@ def load(file_or_path): m = pickle.load(file_or_path) except: import pickle - if isinstance(file_or_path, basestring): + if isinstance(file_or_path, str): with open(file_or_path, 'rb') as f: m = pickle.load(f) else: diff --git a/GPy/__version__.py b/GPy/__version__.py index aa00ec3d..8cce3f28 100644 --- a/GPy/__version__.py +++ b/GPy/__version__.py @@ -1 +1 @@ -__version__ = "0.8.8" +__version__ = "0.8.8dev5" diff --git a/GPy/core/gp.py b/GPy/core/gp.py index 2ed0f280..16b0ca0f 100644 --- a/GPy/core/gp.py +++ b/GPy/core/gp.py @@ -242,7 +242,7 @@ class GP(Model): return mu, var - def predict(self, Xnew, full_cov=False, Y_metadata=None, kern=None): + def predict(self, Xnew, full_cov=False, Y_metadata=None, kern=None, likelihood=None): """ Predict the function(s) at the new point(s) Xnew. @@ -269,10 +269,12 @@ class GP(Model): mu, var = self.normalizer.inverse_mean(mu), self.normalizer.inverse_variance(var) # now push through likelihood - mean, var = self.likelihood.predictive_values(mu, var, full_cov, Y_metadata=Y_metadata) + if likelihood is None: + likelihood = self.likelihood + mean, var = likelihood.predictive_values(mu, var, full_cov, Y_metadata=Y_metadata) return mean, var - def predict_quantiles(self, X, quantiles=(2.5, 97.5), Y_metadata=None, kern=None): + def predict_quantiles(self, X, quantiles=(2.5, 97.5), Y_metadata=None, kern=None, likelihood=None): """ Get the predictive quantiles around the prediction at X @@ -288,9 +290,11 @@ class GP(Model): m, v = self._raw_predict(X, full_cov=False, kern=kern) if self.normalizer is not None: m, v = self.normalizer.inverse_mean(m), self.normalizer.inverse_variance(v) - return self.likelihood.predictive_quantiles(m, v, quantiles, Y_metadata=Y_metadata) + if likelihood is None: + likelihood = self.likelihood + return likelihood.predictive_quantiles(m, v, quantiles, Y_metadata=Y_metadata) - def predictive_gradients(self, Xnew): + def predictive_gradients(self, Xnew, kern=None): """ Compute the derivatives of the predicted latent function with respect to X* @@ -307,16 +311,19 @@ class GP(Model): :rtype: [np.ndarray (N*, Q ,D), np.ndarray (N*,Q) ] """ - dmu_dX = np.empty((Xnew.shape[0],Xnew.shape[1],self.output_dim)) + if kern is None: + kern = self.kern + mean_jac = np.empty((Xnew.shape[0],Xnew.shape[1],self.output_dim)) + for i in range(self.output_dim): - dmu_dX[:,:,i] = self.kern.gradients_X(self.posterior.woodbury_vector[:,i:i+1].T, Xnew, self.X) + mean_jac[:,:,i] = kern.gradients_X(self.posterior.woodbury_vector[:,i:i+1].T, Xnew, self._predictive_variable) # gradients wrt the diagonal part k_{xx} - dv_dX = self.kern.gradients_X(np.eye(Xnew.shape[0]), Xnew) + dv_dX = kern.gradients_X(np.eye(Xnew.shape[0]), Xnew) #grads wrt 'Schur' part K_{xf}K_{ff}^{-1}K_{fx} - alpha = -2.*np.dot(self.kern.K(Xnew, self.X),self.posterior.woodbury_inv) - dv_dX += self.kern.gradients_X(alpha, Xnew, self.X) - return dmu_dX, dv_dX + alpha = -2.*np.dot(kern.K(Xnew, self._predictive_variable), self.posterior.woodbury_inv) + dv_dX += kern.gradients_X(alpha, Xnew, self._predictive_variable) + return mean_jac, dv_dX def predict_jacobian(self, Xnew, kern=None, full_cov=True): @@ -433,7 +440,7 @@ class GP(Model): mag[n] = np.sqrt(np.linalg.det(G[n, :, :])) return mag - def posterior_samples_f(self,X,size=10, full_cov=True): + def posterior_samples_f(self,X, size=10, full_cov=True, **predict_kwargs): """ Samples the posterior GP at the points X. @@ -444,20 +451,32 @@ class GP(Model): :param full_cov: whether to return the full covariance matrix, or just the diagonal. :type full_cov: bool. :returns: fsim: set of simulations - :rtype: np.ndarray (N x samples) + :rtype: np.ndarray (D x N x samples) (if D==1 we flatten out the first dimension) """ - m, v = self._raw_predict(X, full_cov=full_cov) + m, v = self._raw_predict(X, full_cov=full_cov, **predict_kwargs) if self.normalizer is not None: m, v = self.normalizer.inverse_mean(m), self.normalizer.inverse_variance(v) - v = v.reshape(m.size,-1) if len(v.shape)==3 else v - if not full_cov: - fsim = np.random.multivariate_normal(m.flatten(), np.diag(v.flatten()), size).T - else: - fsim = np.random.multivariate_normal(m.flatten(), v, size).T + + def sim_one_dim(m, v): + if not full_cov: + return np.random.multivariate_normal(m.flatten(), np.diag(v.flatten()), size).T + else: + return np.random.multivariate_normal(m.flatten(), v, size).T + if self.output_dim == 1: + return sim_one_dim(m, v) + else: + fsim = np.empty((self.output_dim, self.num_data, size)) + for d in range(self.output_dim): + if full_cov and v.ndim == 3: + fsim[d] = sim_one_dim(m[:, d], v[:, :, d]) + elif (not full_cov) and v.ndim == 2: + fsim[d] = sim_one_dim(m[:, d], v[:, d]) + else: + fsim[d] = sim_one_dim(m[:, d], v) return fsim - def posterior_samples(self, X, size=10, full_cov=False, Y_metadata=None): + def posterior_samples(self, X, size=10, full_cov=False, Y_metadata=None, likelihood=None, **predict_kwargs): """ Samples the posterior GP at the points X. @@ -469,226 +488,18 @@ class GP(Model): :type full_cov: bool. :param noise_model: for mixed noise likelihood, the noise model to use in the samples. :type noise_model: integer. - :returns: Ysim: set of simulations, a Numpy array (N x samples). + :returns: Ysim: set of simulations, + :rtype: np.ndarray (D x N x samples) (if D==1 we flatten out the first dimension) """ - fsim = self.posterior_samples_f(X, size, full_cov=full_cov) - Ysim = self.likelihood.samples(fsim, Y_metadata=Y_metadata) - return Ysim - - def plot_f(self, plot_limits=None, which_data_rows='all', - which_data_ycols='all', fixed_inputs=[], - levels=20, samples=0, fignum=None, ax=None, resolution=None, - plot_raw=True, - linecol=None,fillcol=None, Y_metadata=None, data_symbol='kx', - apply_link=False): - """ - Plot the GP's view of the world, where the data is normalized and before applying a likelihood. - This is a call to plot with plot_raw=True. - Data will not be plotted in this, as the GP's view of the world - may live in another space, or units then the data. - - Can plot only part of the data and part of the posterior functions - using which_data_rowsm which_data_ycols. - - :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 which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :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 fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input index i should be set to value v. - :type fixed_inputs: a list of tuples - :param resolution: the number of intervals to sample the GP on. Defaults to 200 in 1D and 50 (a 50x50 grid) in 2D - :type resolution: int - :param levels: number of levels to plot in a contour plot. - :param levels: for 2D plotting, the number of contour levels to use is ax is None, create a new figure - :type levels: int - :param samples: the number of a posteriori samples to plot - :type samples: int - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - :param linecol: color of line to plot [Tango.colorsHex['darkBlue']] - :type linecol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) as is standard in matplotlib - :param fillcol: color of fill [Tango.colorsHex['lightBlue']] - :type fillcol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) as is standard in matplotlib - :param Y_metadata: additional data associated with Y which may be needed - :type Y_metadata: dict - :param data_symbol: symbol as used matplotlib, by default this is a black cross ('kx') - :type data_symbol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) alongside marker type, as is standard in matplotlib. - :param apply_link: if there is a link function of the likelihood, plot the link(f*) rather than f* - :type apply_link: boolean - """ - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import models_plots - kw = {} - if linecol is not None: - kw['linecol'] = linecol - if fillcol is not None: - kw['fillcol'] = fillcol - return models_plots.plot_fit(self, plot_limits, which_data_rows, - which_data_ycols, fixed_inputs, - levels, samples, fignum, ax, resolution, - plot_raw=plot_raw, Y_metadata=Y_metadata, - data_symbol=data_symbol, apply_link=apply_link, **kw) - - def plot(self, plot_limits=None, which_data_rows='all', - which_data_ycols='all', fixed_inputs=[], - levels=20, samples=0, fignum=None, ax=None, resolution=None, - plot_raw=False, linecol=None,fillcol=None, Y_metadata=None, - data_symbol='kx', predict_kw=None, plot_training_data=True, samples_y=0, apply_link=False): - """ - Plot the posterior of the GP. - - In one dimension, the function is plotted with a shaded region identifying two standard deviations. - - In two dimsensions, a contour-plot shows the mean predicted function - - In higher dimensions, use fixed_inputs to plot the GP with some of the inputs fixed. - - Can plot only part of the data and part of the posterior functions - using which_data_rowsm which_data_ycols. - - :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 which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :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 fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input index i should be set to value v. - :type fixed_inputs: a list of tuples - :param resolution: the number of intervals to sample the GP on. Defaults to 200 in 1D and 50 (a 50x50 grid) in 2D - :type resolution: int - :param levels: number of levels to plot in a contour plot. - :param levels: for 2D plotting, the number of contour levels to use is ax is None, create a new figure - :type levels: int - :param samples: the number of a posteriori samples to plot, p(f*|y) - :type samples: int - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - :param linecol: color of line to plot [Tango.colorsHex['darkBlue']] - :type linecol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) as is standard in matplotlib - :param fillcol: color of fill [Tango.colorsHex['lightBlue']] - :type fillcol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) as is standard in matplotlib - :param Y_metadata: additional data associated with Y which may be needed - :type Y_metadata: dict - :param data_symbol: symbol as used matplotlib, by default this is a black cross ('kx') - :type data_symbol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) alongside marker type, as is standard in matplotlib. - :param plot_training_data: whether or not to plot the training points - :type plot_training_data: boolean - :param samples_y: the number of a posteriori samples to plot, p(y*|y) - :type samples_y: int - :param apply_link: if there is a link function of the likelihood, plot the link(f*) rather than f*, when plotting posterior samples f - :type apply_link: boolean - """ - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import models_plots - kw = {} - if linecol is not None: - kw['linecol'] = linecol - if fillcol is not None: - kw['fillcol'] = fillcol - return models_plots.plot_fit(self, plot_limits, which_data_rows, - which_data_ycols, fixed_inputs, - levels, samples, fignum, ax, resolution, - plot_raw=plot_raw, Y_metadata=Y_metadata, - data_symbol=data_symbol, predict_kw=predict_kw, - plot_training_data=plot_training_data, samples_y=samples_y, apply_link=apply_link, **kw) - - - def plot_data(self, which_data_rows='all', - which_data_ycols='all', visible_dims=None, - fignum=None, ax=None, data_symbol='kx'): - """ - Plot the training data - - For higher dimensions than two, use fixed_inputs to plot the data points with some of the inputs fixed. - - Can plot only part of the data - using which_data_rows and which_data_ycols. - - :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 which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :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 visible_dims: an array specifying the input dimensions to plot (maximum two) - :type visible_dims: a numpy array - :param resolution: the number of intervals to sample the GP on. Defaults to 200 in 1D and 50 (a 50x50 grid) in 2D - :type resolution: int - :param levels: number of levels to plot in a contour plot. - :param levels: for 2D plotting, the number of contour levels to use is ax is None, create a new figure - :type levels: int - :param samples: the number of a posteriori samples to plot, p(f*|y) - :type samples: int - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - :param linecol: color of line to plot [Tango.colorsHex['darkBlue']] - :type linecol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) as is standard in matplotlib - :param fillcol: color of fill [Tango.colorsHex['lightBlue']] - :type fillcol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) as is standard in matplotlib - :param data_symbol: symbol as used matplotlib, by default this is a black cross ('kx') - :type data_symbol: color either as Tango.colorsHex object or character ('r' is red, 'g' is green) alongside marker type, as is standard in matplotlib. - """ - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import models_plots - kw = {} - return models_plots.plot_data(self, which_data_rows, - which_data_ycols, visible_dims, - fignum, ax, data_symbol, **kw) - - - def plot_errorbars_trainset(self, which_data_rows='all', - which_data_ycols='all', fixed_inputs=[], fignum=None, ax=None, - linecol=None, data_symbol='kx', predict_kw=None, plot_training_data=True,lw=None): - - """ - Plot the posterior error bars corresponding to the training data - - For higher dimensions than two, use fixed_inputs to plot the data points with some of the inputs fixed. - - Can plot only part of the data - using which_data_rows and which_data_ycols. - - :param which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :param which_data_ycols: when the data has several columns (independant outputs), only plot these - :type which_data_rows: 'all' or a list of integers - :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input index i should be set to value v. - :type fixed_inputs: a list of tuples - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - :param plot_training_data: whether or not to plot the training points - :type plot_training_data: boolean - """ - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import models_plots - kw = {} - if lw is not None: - kw['lw'] = lw - return models_plots.plot_errorbars_trainset(self, which_data_rows, which_data_ycols, fixed_inputs, - fignum, ax, linecol, data_symbol, - predict_kw, plot_training_data, **kw) - - - def plot_magnification(self, labels=None, which_indices=None, - resolution=50, ax=None, marker='o', s=40, - fignum=None, legend=True, - plot_limits=None, - aspect='auto', updates=False, plot_inducing=True, kern=None, **kwargs): - - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_magnification(self, labels, which_indices, - resolution, ax, marker, s, - fignum, plot_inducing, legend, - plot_limits, aspect, updates, **kwargs) - + fsim = self.posterior_samples_f(X, size, full_cov=full_cov, **predict_kwargs) + if likelihood is None: + likelihood = self.likelihood + if fsim.ndim == 3: + for d in range(fsim.shape[0]): + fsim[d] = likelihood.samples(fsim[d], Y_metadata=Y_metadata) + else: + fsim = likelihood.samples(fsim, Y_metadata=Y_metadata) + return fsim def input_sensitivity(self, summarize=True): """ @@ -696,6 +507,9 @@ class GP(Model): """ return self.kern.input_sensitivity(summarize=summarize) + def get_most_significant_input_dimensions(self, which_indices=None): + return self.kern.get_most_significant_input_dimensions(which_indices) + def optimize(self, optimizer=None, start=None, **kwargs): """ Optimize the model using self.log_likelihood and self.log_likelihood_gradient, as well as self.priors. diff --git a/GPy/core/parameterization/priors.py b/GPy/core/parameterization/priors.py index 2d52bff0..224394ca 100644 --- a/GPy/core/parameterization/priors.py +++ b/GPy/core/parameterization/priors.py @@ -172,7 +172,7 @@ class LogGaussian(Gaussian): return -((np.log(x) - self.mu) / self.sigma2 + 1.) / x def rvs(self, n): - return np.exp(np.random.randn(n) * self.sigma + self.mu) + return np.exp(np.random.randn(int(n)) * self.sigma + self.mu) class MultivariateGaussian(Prior): diff --git a/GPy/defaults.cfg b/GPy/defaults.cfg index aa68a421..b23bb815 100644 --- a/GPy/defaults.cfg +++ b/GPy/defaults.cfg @@ -28,3 +28,6 @@ working = True [cython] working = True + +[plotting] +library = matplotlib \ No newline at end of file diff --git a/GPy/examples/__init__.py b/GPy/examples/__init__.py index 4e9e984e..8c7a5b65 100644 --- a/GPy/examples/__init__.py +++ b/GPy/examples/__init__.py @@ -1,6 +1,11 @@ # Copyright (c) 2012-2014, GPy authors (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) +""" +Examples for GPy. +The examples in this package usually depend on `pods `_ so make sure +you have that installed before running examples. +""" from . import classification from . import regression from . import dimensionality_reduction diff --git a/GPy/examples/classification.py b/GPy/examples/classification.py index ae4e9ba3..af1c8c7a 100644 --- a/GPy/examples/classification.py +++ b/GPy/examples/classification.py @@ -1,7 +1,5 @@ # Copyright (c) 2012-2014, GPy authors (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) - - """ Gaussian Processes classification examples """ diff --git a/GPy/examples/coreg_example.py b/GPy/examples/coreg_example.py deleted file mode 100644 index 3afeb9fb..00000000 --- a/GPy/examples/coreg_example.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) 2012-2014, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - -import numpy as np -try: - from matplotlib import pyplot as pb -except: - pass -import GPy -pb.ion() -pb.close('all') - -X1 = np.arange(3)[:,None] -X2 = np.arange(4)[:,None] -I1 = np.zeros_like(X1) -I2 = np.ones_like(X2) - -_X = np.vstack([ X1, X2 ]) -_I = np.vstack([ I1, I2 ]) - -X = np.hstack([ _X, _I ]) - -Y1 = np.sin(X1/8.) -Y2 = np.cos(X2/8.) - -Bias = GPy.kern.Bias(1,active_dims=[0]) -Coreg = GPy.kern.Coregionalize(1,2,active_dims=[1]) -K = Bias.prod(Coreg,name='X') - -#K.coregion.W = 0 -#print K.coregion.W -#print Bias.K(_X,_X) -#print K.K(X,X) -#pb.matshow(K.K(X,X)) - -Mlist = [GPy.kern.Matern32(1,lengthscale=20.,name="Mat")] -kern = GPy.util.multioutput.LCM(input_dim=1,num_outputs=2,kernels_list=Mlist,name='H') -kern.B.W = 0 -kern.B.kappa = 1. -#kern.B.W.fix() -#kern.B.kappa.fix() -#m = GPy.models.GPCoregionalizedRegression(X_list=[X1,X2], Y_list=[Y1,Y2], kernel=kern) - - -Z1 = np.array([1.5,2.5])[:,None] - -m = GPy.models.SparseGPCoregionalizedRegression(X_list=[X1], Y_list=[Y1], Z_list = [Z1], kernel=kern) -#m.optimize() -m.checkgrad(verbose=1) - -""" -fig = pb.figure() -ax0 = fig.add_subplot(211) -ax1 = fig.add_subplot(212) -slices = GPy.util.multioutput.get_slices([Y1,Y2]) -m.plot(fixed_inputs=[(1,0)],which_data_rows=slices[0],ax=ax0) -#m.plot(fixed_inputs=[(1,1)],which_data_rows=slices[1],ax=ax1) -""" - - - -""" - -X1 = 100 * np.random.rand(100)[:,None] -X2 = 100 * np.random.rand(100)[:,None] -#X1.sort() -#X2.sort() - -Y1 = np.sin(X1/10.) + np.random.rand(100)[:,None] -Y2 = np.cos(X2/10.) + np.random.rand(100)[:,None] - - - - -Mlist = [GPy.kern.Matern32(1,lengthscale=20.,name="Mat")] -kern = GPy.util.multioutput.LCM(input_dim=1,num_outputs=12,kernels_list=Mlist,name='H') - - -m = GPy.models.GPCoregionalizedRegression(X_list=[X1,X2], Y_list=[Y1,Y2], kernel=kern) -m.optimize() - -fig = pb.figure() -ax0 = fig.add_subplot(211) -ax1 = fig.add_subplot(212) -slices = GPy.util.multioutput.get_slices([Y1,Y2]) -m.plot(fixed_inputs=[(1,0)],which_data_rows=slices[0],ax=ax0) -m.plot(fixed_inputs=[(1,1)],which_data_rows=slices[1],ax=ax1) - -""" diff --git a/GPy/examples/dimensionality_reduction.py b/GPy/examples/dimensionality_reduction.py index 9d6686f9..0d72949a 100644 --- a/GPy/examples/dimensionality_reduction.py +++ b/GPy/examples/dimensionality_reduction.py @@ -343,6 +343,29 @@ def bgplvm_simulation(optimize=True, verbose=1, m.kern.plot_ARD('BGPLVM Simulation ARD Parameters') return m +def gplvm_simulation(optimize=True, verbose=1, + plot=True, plot_sim=False, + max_iters=2e4, + ): + from GPy import kern + from GPy.models import GPLVM + + D1, D2, D3, N, num_inducing, Q = 13, 5, 8, 45, 3, 9 + _, _, Ylist = _simulate_matern(D1, D2, D3, N, num_inducing, plot_sim) + Y = Ylist[0] + k = kern.Linear(Q, ARD=True) # + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) + # k = kern.RBF(Q, ARD=True, lengthscale=10.) + m = GPLVM(Y, Q, init="PCA", kernel=k) + m.likelihood.variance = .1 + + if optimize: + print("Optimizing model:") + m.optimize('bfgs', messages=verbose, max_iters=max_iters, + gtol=.05) + if plot: + m.X.plot("BGPLVM Latent Space 1D") + m.kern.plot_ARD('BGPLVM Simulation ARD Parameters') + return m def ssgplvm_simulation(optimize=True, verbose=1, plot=True, plot_sim=False, max_iters=2e4, useGPU=False diff --git a/GPy/inference/optimization/optimization.py b/GPy/inference/optimization/optimization.py index a7e44f2e..1052e909 100644 --- a/GPy/inference/optimization/optimization.py +++ b/GPy/inference/optimization/optimization.py @@ -12,7 +12,7 @@ except ImportError: rasm_available = False from .scg import SCG -class Optimizer(): +class Optimizer(object): """ Superclass for all the optimizers. @@ -56,16 +56,6 @@ class Optimizer(): def opt(self, f_fp=None, f=None, fp=None): raise NotImplementedError("this needs to be implemented to use the optimizer class") - def plot(self): - """ - See GPy.plotting.matplot_dep.inference_plots - """ - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ...plotting.matplot_dep import inference_plots - inference_plots.plot_optimizer(self) - - def __str__(self): diagnostics = "Optimizer: \t\t\t\t %s\n" % self.opt_name diagnostics += "f(x_opt): \t\t\t\t %.3f\n" % self.f_opt diff --git a/GPy/installation.cfg b/GPy/installation.cfg index 901a7ef5..8458a86b 100644 --- a/GPy/installation.cfg +++ b/GPy/installation.cfg @@ -1,2 +1,18 @@ -# This is the local installation configuration file for GPy +# For user specific changes edit $HOME/.config/GPy/user.cfg +# [parallel] +# Enable openmp support. This speeds up some computations, depending on the number +# of cores available. Setting up a compiler with openmp support can be difficult on +# some platforms, hence by default it is off. +# openmp = False # True + +# [datasets] +# location for the local data cache +# dir=$HOME/tmp/GPy-datasets/ # Any other path you choose + +# [cython] +# working = True # False + + +# [plotting] +# library = matplotlib # plotly diff --git a/GPy/kern/__init__.py b/GPy/kern/__init__.py index c4464db9..f8f7d016 100644 --- a/GPy/kern/__init__.py +++ b/GPy/kern/__init__.py @@ -1,24 +1,31 @@ -from ._src.kern import Kern -from ._src.rbf import RBF -from ._src.linear import Linear, LinearFull -from ._src.static import Bias, White, Fixed -from ._src.brownian import Brownian -from ._src.stationary import Exponential, OU, Matern32, Matern52, ExpQuad, RatQuad, Cosine -from ._src.mlp import MLP -from ._src.periodic import PeriodicExponential, PeriodicMatern32, PeriodicMatern52 -from ._src.standard_periodic import StdPeriodic -from ._src.independent_outputs import IndependentOutputs, Hierarchical -from ._src.coregionalize import Coregionalize -from ._src.ODE_UY import ODE_UY -from ._src.ODE_UYC import ODE_UYC -from ._src.ODE_st import ODE_st -from ._src.ODE_t import ODE_t -from ._src.poly import Poly -from ._src.eq_ode2 import EQ_ODE2 -from ._src.trunclinear import TruncLinear,TruncLinear_inf -from ._src.splitKern import SplitKern,DEtime -from ._src.splitKern import DEtime as DiffGenomeKern -from ._src.spline import Spline -from ._src.eq_ode2 import EQ_ODE2 -from ._src.basis_funcs import LinearSlopeBasisFuncKernel, BasisFuncKernel, ChangePointBasisFuncKernel, DomainKernel +""" +Kernel module the kernels to sit in. +.. automodule:: .src + :members: + :private-members: +""" +from .src.kern import Kern +from .src.add import Add +from .src.prod import Prod +from .src.rbf import RBF +from .src.linear import Linear, LinearFull +from .src.static import Bias, White, Fixed +from .src.brownian import Brownian +from .src.stationary import Exponential, OU, Matern32, Matern52, ExpQuad, RatQuad, Cosine +from .src.mlp import MLP +from .src.periodic import PeriodicExponential, PeriodicMatern32, PeriodicMatern52 +from .src.standard_periodic import StdPeriodic +from .src.independent_outputs import IndependentOutputs, Hierarchical +from .src.coregionalize import Coregionalize +from .src.ODE_UY import ODE_UY +from .src.ODE_UYC import ODE_UYC +from .src.ODE_st import ODE_st +from .src.ODE_t import ODE_t +from .src.poly import Poly +from .src.eq_ode2 import EQ_ODE2 +from .src.trunclinear import TruncLinear,TruncLinear_inf +from .src.splitKern import SplitKern,DEtime +from .src.splitKern import DEtime as DiffGenomeKern +from .src.spline import Spline +from .src.basis_funcs import LinearSlopeBasisFuncKernel, BasisFuncKernel, ChangePointBasisFuncKernel, DomainKernel \ No newline at end of file diff --git a/GPy/kern/_src/ODE_UY.py b/GPy/kern/src/ODE_UY.py similarity index 100% rename from GPy/kern/_src/ODE_UY.py rename to GPy/kern/src/ODE_UY.py index 9c9b47be..ae9c4574 100644 --- a/GPy/kern/_src/ODE_UY.py +++ b/GPy/kern/src/ODE_UY.py @@ -2,10 +2,10 @@ # Licensed under the BSD 3-clause license (see LICENSE.txt) from .kern import Kern +from .independent_outputs import index_to_slices from ...core.parameterization import Param from ...core.parameterization.transformations import Logexp import numpy as np -from .independent_outputs import index_to_slices class ODE_UY(Kern): def __init__(self, input_dim, variance_U=3., variance_Y=1., lengthscale_U=1., lengthscale_Y=1., active_dims=None, name='ode_uy'): diff --git a/GPy/kern/_src/ODE_UYC.py b/GPy/kern/src/ODE_UYC.py similarity index 100% rename from GPy/kern/_src/ODE_UYC.py rename to GPy/kern/src/ODE_UYC.py diff --git a/GPy/kern/_src/ODE_st.py b/GPy/kern/src/ODE_st.py similarity index 100% rename from GPy/kern/_src/ODE_st.py rename to GPy/kern/src/ODE_st.py diff --git a/GPy/kern/_src/ODE_t.py b/GPy/kern/src/ODE_t.py similarity index 100% rename from GPy/kern/_src/ODE_t.py rename to GPy/kern/src/ODE_t.py diff --git a/GPy/kern/src/__init__.py b/GPy/kern/src/__init__.py new file mode 100644 index 00000000..d90842ca --- /dev/null +++ b/GPy/kern/src/__init__.py @@ -0,0 +1 @@ +from . import psi_comp \ No newline at end of file diff --git a/GPy/kern/_src/add.py b/GPy/kern/src/add.py similarity index 92% rename from GPy/kern/_src/add.py rename to GPy/kern/src/add.py index 6893011d..9f80ac9d 100644 --- a/GPy/kern/_src/add.py +++ b/GPy/kern/src/add.py @@ -121,7 +121,7 @@ class Add(CombinationKernel): #ffrom fixed import Fixed for p1, p2 in itertools.combinations(self.parts, 2): - # i1, i2 = p1.active_dims, p2.active_dims + # i1, i2 = p1._all_dims_active, p2._all_dims_active # white doesn;t combine with anything if isinstance(p1, White) or isinstance(p2, White): pass @@ -135,7 +135,7 @@ class Add(CombinationKernel): tmp = p1.psi1(Z, variational_posterior).sum(axis=0) psi2 += p2.variance * (tmp[:,None]+tmp[None,:]) #(tmp[:, :, None] + tmp[:, None, :]) elif isinstance(p2, (RBF, Linear)) and isinstance(p1, (RBF, Linear)): - assert np.intersect1d(p1.active_dims, p2.active_dims).size == 0, "only non overlapping kernel dimensions allowed so far" + assert np.intersect1d(p1._all_dims_active, p2._all_dims_active).size == 0, "only non overlapping kernel dimensions allowed so far" tmp1 = p1.psi1(Z, variational_posterior) tmp2 = p2.psi1(Z, variational_posterior) psi2 += np.einsum('nm,no->mo',tmp1,tmp2)+np.einsum('nm,no->mo',tmp2,tmp1) @@ -157,7 +157,7 @@ class Add(CombinationKernel): #ffrom fixed import Fixed for p1, p2 in itertools.combinations(self.parts, 2): - # i1, i2 = p1.active_dims, p2.active_dims + # i1, i2 = p1._all_dims_active, p2._all_dims_active # white doesn;t combine with anything if isinstance(p1, White) or isinstance(p2, White): pass @@ -171,7 +171,7 @@ class Add(CombinationKernel): tmp = p1.psi1(Z, variational_posterior) psi2 += p2.variance * (tmp[:, :, None] + tmp[:, None, :]) elif isinstance(p2, (RBF, Linear)) and isinstance(p1, (RBF, Linear)): - assert np.intersect1d(p1.active_dims, p2.active_dims).size == 0, "only non overlapping kernel dimensions allowed so far" + assert np.intersect1d(p1._all_dims_active, p2._all_dims_active).size == 0, "only non overlapping kernel dimensions allowed so far" tmp1 = p1.psi1(Z, variational_posterior) tmp2 = p2.psi1(Z, variational_posterior) psi2 += np.einsum('nm,no->nmo',tmp1,tmp2)+np.einsum('nm,no->nmo',tmp2,tmp1) @@ -193,7 +193,7 @@ class Add(CombinationKernel): continue elif isinstance(p2, Bias): eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.variance * 2. - else:# np.setdiff1d(p1.active_dims, ar2, assume_unique): # TODO: Careful, not correct for overlapping active_dims + else:# np.setdiff1d(p1._all_dims_active, ar2, assume_unique): # TODO: Careful, not correct for overlapping _all_dims_active eff_dL_dpsi1 += dL_dpsi2.sum(1) * p2.psi1(Z, variational_posterior) * 2. p1.update_gradients_expectations(dL_dpsi0, eff_dL_dpsi1, dL_dpsi2, Z, variational_posterior) @@ -244,17 +244,14 @@ class Add(CombinationKernel): self.link_parameters(*other_params) else: self.link_parameter(other) - self.input_dim, self.active_dims = self.get_input_dim_active_dims(self.parts) + self.input_dim, self._all_dims_active = self.get_input_dim_active_dims(self.parts) return self def input_sensitivity(self, summarize=True): if summarize: i_s = np.zeros((self.input_dim)) for k in self.parts: - i_s[k.active_dims] += k.input_sensitivity(summarize) + i_s[k._all_dims_active] += k.input_sensitivity(summarize) return i_s else: - i_s = np.zeros((len(self.parts), self.input_dim)) - from operator import setitem - [setitem(i_s, (i, k.active_dims), k.input_sensitivity(summarize)) for i, k in enumerate(self.parts)] - return i_s + return super(Add, self).input_sensitivity(summarize) diff --git a/GPy/kern/_src/basis_funcs.py b/GPy/kern/src/basis_funcs.py similarity index 100% rename from GPy/kern/_src/basis_funcs.py rename to GPy/kern/src/basis_funcs.py index dc21a687..3d644af2 100644 --- a/GPy/kern/_src/basis_funcs.py +++ b/GPy/kern/src/basis_funcs.py @@ -1,9 +1,9 @@ # #Copyright (c) 2012, Max Zwiessele (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) +import numpy as np from .kern import Kern from ...core.parameterization.param import Param from ...core.parameterization.transformations import Logexp -import numpy as np from ...util.caching import Cache_this from ...util.linalg import tdot, mdot diff --git a/GPy/kern/_src/brownian.py b/GPy/kern/src/brownian.py similarity index 100% rename from GPy/kern/_src/brownian.py rename to GPy/kern/src/brownian.py diff --git a/GPy/kern/_src/coregionalize.py b/GPy/kern/src/coregionalize.py similarity index 100% rename from GPy/kern/_src/coregionalize.py rename to GPy/kern/src/coregionalize.py diff --git a/GPy/kern/_src/coregionalize_cython.c b/GPy/kern/src/coregionalize_cython.c similarity index 100% rename from GPy/kern/_src/coregionalize_cython.c rename to GPy/kern/src/coregionalize_cython.c diff --git a/GPy/kern/_src/coregionalize_cython.pyx b/GPy/kern/src/coregionalize_cython.pyx similarity index 100% rename from GPy/kern/_src/coregionalize_cython.pyx rename to GPy/kern/src/coregionalize_cython.pyx diff --git a/GPy/kern/_src/eq_ode2.py b/GPy/kern/src/eq_ode2.py similarity index 100% rename from GPy/kern/_src/eq_ode2.py rename to GPy/kern/src/eq_ode2.py diff --git a/GPy/kern/_src/independent_outputs.py b/GPy/kern/src/independent_outputs.py similarity index 99% rename from GPy/kern/_src/independent_outputs.py rename to GPy/kern/src/independent_outputs.py index e9c575bf..5fd22b15 100644 --- a/GPy/kern/_src/independent_outputs.py +++ b/GPy/kern/src/independent_outputs.py @@ -2,7 +2,7 @@ # Licensed under the BSD 3-clause license (see LICENSE.txt) -from .kern import Kern, CombinationKernel +from .kern import CombinationKernel import numpy as np import itertools diff --git a/GPy/kern/_src/kern.py b/GPy/kern/src/kern.py similarity index 73% rename from GPy/kern/_src/kern.py rename to GPy/kern/src/kern.py index 1cc0c0ba..c3d98a9b 100644 --- a/GPy/kern/_src/kern.py +++ b/GPy/kern/src/kern.py @@ -1,12 +1,11 @@ # Copyright (c) 2012, GPy authors (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) - import sys import numpy as np from ...core.parameterization.parameterized import Parameterized -from .kernel_slice_operations import KernCallsViaSlicerMeta +from ...core.parameterization.observable_array import ObsAr from ...util.caching import Cache_this -from GPy.core.parameterization.observable_array import ObsAr +from .kernel_slice_operations import KernCallsViaSlicerMeta from functools import reduce import six @@ -34,15 +33,15 @@ class Kern(Parameterized): If this is not an integer (!) we will work on the whole input matrix X, and not check whether dimensions match or not (!). - active_dims: + _all_dims_active: is the active_dimensions of inputs X we will work on. - All kernels will get sliced Xes as inputs, if active_dims is not None - Only positive integers are allowed in active_dims! - if active_dims is None, slicing is switched off and all X will be passed through as given. + All kernels will get sliced Xes as inputs, if _all_dims_active is not None + Only positive integers are allowed in _all_dims_active! + if _all_dims_active is None, slicing is switched off and all X will be passed through as given. :param int input_dim: the number of input dimensions to the function - :param array-like|None active_dims: list of indices on which dimensions this kernel works on, or none if no slicing + :param array-like|None _all_dims_active: list of indices on which dimensions this kernel works on, or none if no slicing Do not instantiate. """ @@ -52,19 +51,20 @@ class Kern(Parameterized): if active_dims is None: active_dims = np.arange(input_dim) - self.active_dims = np.atleast_1d(active_dims).astype(int) + self.active_dims = active_dims + self._all_dims_active = np.atleast_1d(active_dims).astype(int) - assert self.active_dims.size == self.input_dim, "input_dim={} does not match len(active_dim)={}, active_dims={}".format(self.input_dim, self.active_dims.size, self.active_dims) + assert self._all_dims_active.size == self.input_dim, "input_dim={} does not match len(active_dim)={}, _all_dims_active={}".format(self.input_dim, self._all_dims_active.size, self._all_dims_active) self._sliced_X = 0 self.useGPU = self._support_GPU and useGPU from .psi_comp import PSICOMP_GH - self.psicomp = PSICOMP_GH() + self.psicomp = PSICOMP_GH() @Cache_this(limit=20) def _slice_X(self, X): - return X[:, self.active_dims] + return X[:, self._all_dims_active] def K(self, X, X2): """ @@ -198,21 +198,43 @@ class Kern(Parameterized): from ...plotting.matplot_dep import kernel_plots kernel_plots.plot(self, x, fignum, ax, title, plot_limits, resolution, **mpl_kwargs) - def plot_ARD(self, *args, **kw): - """ - See :class:`~GPy.plotting.matplot_dep.kernel_plots` - """ - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ...plotting.matplot_dep import kernel_plots - return kernel_plots.plot_ARD(self,*args,**kw) - def input_sensitivity(self, summarize=True): """ Returns the sensitivity for each dimension of this kernel. """ return np.zeros(self.input_dim) + def get_most_significant_input_dimensions(self, which_indices=None): + """ + Determine which dimensions should be plotted + + Returns the top three most signification input dimensions + + if less then three dimensions, the non existing dimensions are + labeled as None, so for a 1 dimensional input this returns + (0, None, None). + + :param which_indices: force the indices to be the given indices. + :type which_indices: int or tuple(int,int) or tuple(int,int,int) + """ + if which_indices is None: + which_indices = np.argsort(self.input_sensitivity())[::-1][:3] + try: + input_1, input_2, input_3 = which_indices + except ValueError: + # which indices is tuple or int + try: + input_3 = None + input_1, input_2 = which_indices + except TypeError: + # which_indices is an int + input_1, input_2 = which_indices, None + except ValueError: + # which_indices was a list or array like with only one int + input_1, input_2 = which_indices[0], None + return input_1, input_2, input_3 + + def __add__(self, other): """ Overloading of the '+' operator. for more control, see self.add """ return self.add(other) @@ -244,9 +266,9 @@ class Kern(Parameterized): """ Shortcut for tensor `prod`. """ - assert np.all(self.active_dims == range(self.input_dim)), "Can only use kernels, which have their input_dims defined from 0" - assert np.all(other.active_dims == range(other.input_dim)), "Can only use kernels, which have their input_dims defined from 0" - other.active_dims += self.input_dim + assert np.all(self._all_dims_active == range(self.input_dim)), "Can only use kernels, which have their input_dims defined from 0" + assert np.all(other._all_dims_active == range(other.input_dim)), "Can only use kernels, which have their input_dims defined from 0" + other._all_dims_active += self.input_dim return self.prod(other) def prod(self, other, name='mul'): @@ -268,10 +290,10 @@ class Kern(Parameterized): return Prod([self, other], name) def _check_input_dim(self, X): - assert X.shape[1] == self.input_dim, "{} did not specify active_dims and X has wrong shape: X_dim={}, whereas input_dim={}".format(self.name, X.shape[1], self.input_dim) + assert X.shape[1] == self.input_dim, "{} did not specify _all_dims_active and X has wrong shape: X_dim={}, whereas input_dim={}".format(self.name, X.shape[1], self.input_dim) def _check_active_dims(self, X): - assert X.shape[1] >= len(self.active_dims), "At least {} dimensional X needed, X.shape={!s}".format(len(self.active_dims), X.shape) + assert X.shape[1] >= len(self._all_dims_active), "At least {} dimensional X needed, X.shape={!s}".format(len(self._all_dims_active), X.shape) class CombinationKernel(Kern): @@ -303,15 +325,15 @@ class CombinationKernel(Kern): return self.parameters def get_input_dim_active_dims(self, kernels, extra_dims = None): - #active_dims = reduce(np.union1d, (np.r_[x.active_dims] for x in kernels), np.array([], dtype=int)) - #active_dims = np.array(np.concatenate((active_dims, extra_dims if extra_dims is not None else [])), dtype=int) - input_dim = reduce(max, (k.active_dims.max() for k in kernels)) + 1 + self.active_dims = reduce(np.union1d, (np.r_[x.active_dims] for x in kernels), np.array([], dtype=int)) + #_all_dims_active = np.array(np.concatenate((_all_dims_active, extra_dims if extra_dims is not None else [])), dtype=int) + input_dim = reduce(max, (k._all_dims_active.max() for k in kernels)) + 1 if extra_dims is not None: input_dim += extra_dims.size - active_dims = np.arange(input_dim) - return input_dim, active_dims + _all_dims_active = np.arange(input_dim) + return input_dim, _all_dims_active def input_sensitivity(self, summarize=True): """ @@ -319,7 +341,20 @@ class CombinationKernel(Kern): otherwise put everything into an array with shape (#kernels, input_dim) in the order of appearance of the kernels in the parameterized object. """ - raise NotImplementedError("Choose the kernel you want to get the sensitivity for. You need to override the default behaviour for getting the input sensitivity to be able to get the input sensitivity. For sum kernel it is the sum of all sensitivities, TODO: product kernel? Other kernels?, also TODO: shall we return all the sensitivities here in the combination kernel? So we can combine them however we want? This could lead to just plot all the sensitivities here...") + if not summarize: + num_params = [0] + parts = [] + def sum_params(x): + if (not isinstance(x, CombinationKernel)) and isinstance(x, Kern): + num_params[0] += 1 + parts.append(x) + self.traverse(sum_params) + i_s = np.zeros((num_params[0], self.input_dim)) + from operator import setitem + [setitem(i_s, (i, k._all_dims_active), k.input_sensitivity(summarize)) for i, k in enumerate(parts)] + return i_s + else: + raise NotImplementedError("Choose the kernel you want to get the sensitivity for. You need to override the default behaviour for getting the input sensitivity to be able to get the input sensitivity. For sum kernel it is the sum of all sensitivities, TODO: product kernel? Other kernels?, also TODO: shall we return all the sensitivities here in the combination kernel? So we can combine them however we want? This could lead to just plot all the sensitivities here...") def _check_active_dims(self, X): return diff --git a/GPy/kern/_src/kernel_slice_operations.py b/GPy/kern/src/kernel_slice_operations.py similarity index 94% rename from GPy/kern/_src/kernel_slice_operations.py rename to GPy/kern/src/kernel_slice_operations.py index 719d6b56..2bd1f923 100644 --- a/GPy/kern/_src/kernel_slice_operations.py +++ b/GPy/kern/src/kernel_slice_operations.py @@ -5,7 +5,7 @@ Created on 11 Mar 2014 This module provides a meta class for the kernels. The meta class is for slicing the inputs (X, X2) for the kernels, before K (or any other method involving X) -gets calls. The `active_dims` of a kernel decide which dimensions the kernel works on. +gets calls. The `_all_dims_active` of a kernel decide which dimensions the kernel works on. ''' from ...core.parameterization.parameterized import ParametersChangedMeta import numpy as np @@ -13,7 +13,7 @@ from functools import wraps def put_clean(dct, name, func): if name in dct: - dct['_clean_{}'.format(name)] = dct[name] + #dct['_clean_{}'.format(name)] = dct[name] dct[name] = func(dct[name]) class KernCallsViaSlicerMeta(ParametersChangedMeta): @@ -47,7 +47,7 @@ class _Slice_wrap(object): assert X.ndim == 2, "only matrices are allowed as inputs to kernels for now, given X.shape={!s}".format(X.shape) if X2 is not None: assert X2.ndim == 2, "only matrices are allowed as inputs to kernels for now, given X2.shape={!s}".format(X2.shape) - if (self.k.active_dims is not None) and (self.k._sliced_X == 0): + if (self.k._all_dims_active is not None) and (self.k._sliced_X == 0): self.k._check_active_dims(X) self.X = self.k._slice_X(X) self.X2 = self.k._slice_X(X2) if X2 is not None else X2 @@ -66,9 +66,9 @@ class _Slice_wrap(object): if self.ret: ret = np.zeros(self.shape) if len(self.shape) == 2: - ret[:, self.k.active_dims] = return_val + ret[:, self.k._all_dims_active] = return_val elif len(self.shape) == 3: - ret[:, :, self.k.active_dims] = return_val + ret[:, :, self.k._all_dims_active] = return_val return ret return return_val diff --git a/GPy/kern/_src/linear.py b/GPy/kern/src/linear.py similarity index 98% rename from GPy/kern/_src/linear.py rename to GPy/kern/src/linear.py index 0a582ac8..25f6299d 100644 --- a/GPy/kern/_src/linear.py +++ b/GPy/kern/src/linear.py @@ -8,7 +8,6 @@ from ...util.linalg import tdot from ...core.parameterization import Param from ...core.parameterization.transformations import Logexp from ...util.caching import Cache_this -from ...util.config import * from .psi_comp import PSICOMP_Linear class Linear(Kern): @@ -109,6 +108,9 @@ class Linear(Kern): def gradients_X_diag(self, dL_dKdiag, X): return 2.*self.variances*dL_dKdiag[:,None]*X + def gradients_XX_diag(self, dL_dKdiag, X): + return 2*np.ones(X.shape)*self.variances + def input_sensitivity(self, summarize=True): return np.ones(self.input_dim) * self.variances diff --git a/GPy/kern/_src/mlp.py b/GPy/kern/src/mlp.py similarity index 99% rename from GPy/kern/_src/mlp.py rename to GPy/kern/src/mlp.py index 40a8d2d7..8f9a276c 100644 --- a/GPy/kern/_src/mlp.py +++ b/GPy/kern/src/mlp.py @@ -5,7 +5,6 @@ from .kern import Kern from ...core.parameterization import Param from ...core.parameterization.transformations import Logexp import numpy as np -from ...util.linalg import tdot from ...util.caching import Cache_this four_over_tau = 2./np.pi diff --git a/GPy/kern/_src/periodic.py b/GPy/kern/src/periodic.py similarity index 99% rename from GPy/kern/_src/periodic.py rename to GPy/kern/src/periodic.py index 014909ef..4c4d2234 100644 --- a/GPy/kern/_src/periodic.py +++ b/GPy/kern/src/periodic.py @@ -8,7 +8,6 @@ from ...util.linalg import mdot from ...util.decorators import silence_errors from ...core.parameterization.param import Param from ...core.parameterization.transformations import Logexp -from functools import reduce class Periodic(Kern): def __init__(self, input_dim, variance, lengthscale, period, n_freq, lower, upper, active_dims, name): diff --git a/GPy/kern/_src/poly.py b/GPy/kern/src/poly.py similarity index 100% rename from GPy/kern/_src/poly.py rename to GPy/kern/src/poly.py diff --git a/GPy/kern/_src/prod.py b/GPy/kern/src/prod.py similarity index 92% rename from GPy/kern/_src/prod.py rename to GPy/kern/src/prod.py index b47e663d..68883af4 100644 --- a/GPy/kern/_src/prod.py +++ b/GPy/kern/src/prod.py @@ -97,4 +97,11 @@ class Prod(CombinationKernel): target += p.gradients_X_diag(k/p.Kdiag(X),X) return target - + def input_sensitivity(self, summarize=True): + if summarize: + i_s = np.zeros((self.input_dim)) + for k in self.parts: + i_s[k._all_dims_active] *= k.input_sensitivity(summarize) + return i_s + else: + return super(Prod, self).input_sensitivity(summarize) diff --git a/GPy/kern/_src/psi_comp/__init__.py b/GPy/kern/src/psi_comp/__init__.py similarity index 93% rename from GPy/kern/_src/psi_comp/__init__.py rename to GPy/kern/src/psi_comp/__init__.py index 5cee363d..90ceca6b 100644 --- a/GPy/kern/_src/psi_comp/__init__.py +++ b/GPy/kern/src/psi_comp/__init__.py @@ -2,13 +2,9 @@ # Licensed under the BSD 3-clause license (see LICENSE.txt) from ....core.parameterization.parameter_core import Pickleable -from GPy.util.caching import Cache_this +from ....util.caching import Cache_this from ....core.parameterization import variational -from . import rbf_psi_comp -from . import ssrbf_psi_comp -from . import sslinear_psi_comp -from . import linear_psi_comp - +#from linear_psi_comp import LINEAr class PSICOMP(Pickleable): @@ -22,6 +18,7 @@ class PSICOMP(Pickleable): pass from .gaussherm import PSICOMP_GH +from . import rbf_psi_comp, linear_psi_comp, ssrbf_psi_comp, sslinear_psi_comp class PSICOMP_RBF(PSICOMP): @Cache_this(limit=10, ignore_args=(0,)) @@ -67,3 +64,5 @@ class PSICOMP_Linear(PSICOMP): raise ValueError("unknown distriubtion received for psi-statistics") +from . import ssrbf_psi_gpucomp +from .rbf_psi_gpucomp import PSICOMP_RBF_GPU diff --git a/GPy/kern/_src/psi_comp/gaussherm.py b/GPy/kern/src/psi_comp/gaussherm.py similarity index 98% rename from GPy/kern/_src/psi_comp/gaussherm.py rename to GPy/kern/src/psi_comp/gaussherm.py index be4856b4..35eab724 100644 --- a/GPy/kern/_src/psi_comp/gaussherm.py +++ b/GPy/kern/src/psi_comp/gaussherm.py @@ -8,10 +8,12 @@ An approximated psi-statistics implementation based on Gauss-Hermite Quadrature import numpy as np from ....core.parameterization import Param -from GPy.util.caching import Cache_this +from ....util.caching import Cache_this from ....util.linalg import tdot from . import PSICOMP + + class PSICOMP_GH(PSICOMP): def __init__(self, degree=5, cache_K=True): diff --git a/GPy/kern/_src/psi_comp/linear_psi_comp.py b/GPy/kern/src/psi_comp/linear_psi_comp.py similarity index 100% rename from GPy/kern/_src/psi_comp/linear_psi_comp.py rename to GPy/kern/src/psi_comp/linear_psi_comp.py diff --git a/GPy/kern/_src/psi_comp/rbf_psi_comp.py b/GPy/kern/src/psi_comp/rbf_psi_comp.py similarity index 100% rename from GPy/kern/_src/psi_comp/rbf_psi_comp.py rename to GPy/kern/src/psi_comp/rbf_psi_comp.py diff --git a/GPy/kern/_src/psi_comp/rbf_psi_gpucomp.py b/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py similarity index 99% rename from GPy/kern/_src/psi_comp/rbf_psi_gpucomp.py rename to GPy/kern/src/psi_comp/rbf_psi_gpucomp.py index e2a5c7d1..50945db6 100644 --- a/GPy/kern/_src/psi_comp/rbf_psi_gpucomp.py +++ b/GPy/kern/src/psi_comp/rbf_psi_gpucomp.py @@ -235,7 +235,6 @@ gpu_code = """ class PSICOMP_RBF_GPU(PSICOMP_RBF): def __init__(self, threadnum=256, blocknum=30, GPU_direct=False): - from . import PSICOMP_RBF self.fall_back = PSICOMP_RBF() from pycuda.compiler import SourceModule diff --git a/GPy/kern/_src/psi_comp/sslinear_psi_comp.py b/GPy/kern/src/psi_comp/sslinear_psi_comp.py similarity index 100% rename from GPy/kern/_src/psi_comp/sslinear_psi_comp.py rename to GPy/kern/src/psi_comp/sslinear_psi_comp.py diff --git a/GPy/kern/_src/psi_comp/ssrbf_psi_comp.py b/GPy/kern/src/psi_comp/ssrbf_psi_comp.py similarity index 100% rename from GPy/kern/_src/psi_comp/ssrbf_psi_comp.py rename to GPy/kern/src/psi_comp/ssrbf_psi_comp.py diff --git a/GPy/kern/_src/psi_comp/ssrbf_psi_gpucomp.py b/GPy/kern/src/psi_comp/ssrbf_psi_gpucomp.py similarity index 100% rename from GPy/kern/_src/psi_comp/ssrbf_psi_gpucomp.py rename to GPy/kern/src/psi_comp/ssrbf_psi_gpucomp.py diff --git a/GPy/kern/_src/rbf.py b/GPy/kern/src/rbf.py similarity index 95% rename from GPy/kern/_src/rbf.py rename to GPy/kern/src/rbf.py index f4fb2ad5..3607bea9 100644 --- a/GPy/kern/_src/rbf.py +++ b/GPy/kern/src/rbf.py @@ -4,11 +4,9 @@ import numpy as np from .stationary import Stationary -from .psi_comp import PSICOMP_RBF -from .psi_comp.rbf_psi_gpucomp import PSICOMP_RBF_GPU -from ...util.config import * +from .psi_comp import PSICOMP_RBF, PSICOMP_RBF_GPU from ...core import Param -from GPy.core.parameterization.transformations import Logexp +from ...core.parameterization.transformations import Logexp class RBF(Stationary): """ diff --git a/GPy/kern/_src/spline.py b/GPy/kern/src/spline.py similarity index 99% rename from GPy/kern/_src/spline.py rename to GPy/kern/src/spline.py index 233cf7e8..c1b28764 100644 --- a/GPy/kern/_src/spline.py +++ b/GPy/kern/src/spline.py @@ -5,6 +5,7 @@ import numpy as np from .kern import Kern from ...core.parameterization import Param from ...core.parameterization.transformations import Logexp + class Spline(Kern): """ Linear spline kernel. You need to specify 2 parameters: the variance and c. diff --git a/GPy/kern/_src/splitKern.py b/GPy/kern/src/splitKern.py similarity index 98% rename from GPy/kern/_src/splitKern.py rename to GPy/kern/src/splitKern.py index c131dcd8..324178d4 100644 --- a/GPy/kern/_src/splitKern.py +++ b/GPy/kern/src/splitKern.py @@ -3,7 +3,7 @@ A new kernel """ import numpy as np -from .kern import Kern,CombinationKernel +from .kern import Kern, CombinationKernel from .independent_outputs import index_to_slices import itertools @@ -13,7 +13,7 @@ class DEtime(Kern): self.idx_p = idx_p self.index_dim=index_dim self.kern = SplitKern(kernel,Xp, index_dim=index_dim) - super(DiffGenomeKern, self).__init__(input_dim=kernel.input_dim+1, active_dims=None, name=name) + super(DEtime, self).__init__(input_dim=kernel.input_dim+1, active_dims=None, name=name) self.add_parameter(self.kern) def K(self, X, X2=None): diff --git a/GPy/kern/_src/standard_periodic.py b/GPy/kern/src/standard_periodic.py similarity index 100% rename from GPy/kern/_src/standard_periodic.py rename to GPy/kern/src/standard_periodic.py diff --git a/GPy/kern/_src/static.py b/GPy/kern/src/static.py similarity index 100% rename from GPy/kern/_src/static.py rename to GPy/kern/src/static.py diff --git a/GPy/kern/_src/stationary.py b/GPy/kern/src/stationary.py similarity index 100% rename from GPy/kern/_src/stationary.py rename to GPy/kern/src/stationary.py diff --git a/GPy/kern/_src/stationary_cython.c b/GPy/kern/src/stationary_cython.c similarity index 100% rename from GPy/kern/_src/stationary_cython.c rename to GPy/kern/src/stationary_cython.c diff --git a/GPy/kern/_src/stationary_cython.pyx b/GPy/kern/src/stationary_cython.pyx similarity index 100% rename from GPy/kern/_src/stationary_cython.pyx rename to GPy/kern/src/stationary_cython.pyx diff --git a/GPy/kern/_src/stationary_utils.c b/GPy/kern/src/stationary_utils.c similarity index 100% rename from GPy/kern/_src/stationary_utils.c rename to GPy/kern/src/stationary_utils.c diff --git a/GPy/kern/_src/stationary_utils.h b/GPy/kern/src/stationary_utils.h similarity index 100% rename from GPy/kern/_src/stationary_utils.h rename to GPy/kern/src/stationary_utils.h diff --git a/GPy/kern/_src/symbolic.py b/GPy/kern/src/symbolic.py similarity index 98% rename from GPy/kern/_src/symbolic.py rename to GPy/kern/src/symbolic.py index c339893a..0d855bbb 100644 --- a/GPy/kern/_src/symbolic.py +++ b/GPy/kern/src/symbolic.py @@ -1,7 +1,7 @@ # Check Matthew Rocklin's blog post. import sympy as sym import numpy as np -from .kern import Kern +from GPy.kern.src import Kern from ...core.symbolic import Symbolic_core diff --git a/GPy/kern/_src/sympy_helpers.cpp b/GPy/kern/src/sympy_helpers.cpp similarity index 100% rename from GPy/kern/_src/sympy_helpers.cpp rename to GPy/kern/src/sympy_helpers.cpp diff --git a/GPy/kern/_src/sympy_helpers.h b/GPy/kern/src/sympy_helpers.h similarity index 100% rename from GPy/kern/_src/sympy_helpers.h rename to GPy/kern/src/sympy_helpers.h diff --git a/GPy/kern/_src/todo/ODE_1.py b/GPy/kern/src/todo/ODE_1.py similarity index 100% rename from GPy/kern/_src/todo/ODE_1.py rename to GPy/kern/src/todo/ODE_1.py diff --git a/GPy/kern/_src/todo/eq_ode1.py b/GPy/kern/src/todo/eq_ode1.py similarity index 100% rename from GPy/kern/_src/todo/eq_ode1.py rename to GPy/kern/src/todo/eq_ode1.py diff --git a/GPy/kern/_src/todo/finite_dimensional.py b/GPy/kern/src/todo/finite_dimensional.py similarity index 100% rename from GPy/kern/_src/todo/finite_dimensional.py rename to GPy/kern/src/todo/finite_dimensional.py diff --git a/GPy/kern/_src/todo/fixed.py b/GPy/kern/src/todo/fixed.py similarity index 100% rename from GPy/kern/_src/todo/fixed.py rename to GPy/kern/src/todo/fixed.py diff --git a/GPy/kern/_src/todo/gibbs.py b/GPy/kern/src/todo/gibbs.py similarity index 100% rename from GPy/kern/_src/todo/gibbs.py rename to GPy/kern/src/todo/gibbs.py diff --git a/GPy/kern/_src/todo/hetero.py b/GPy/kern/src/todo/hetero.py similarity index 100% rename from GPy/kern/_src/todo/hetero.py rename to GPy/kern/src/todo/hetero.py diff --git a/GPy/kern/_src/todo/odekern1.c b/GPy/kern/src/todo/odekern1.c similarity index 100% rename from GPy/kern/_src/todo/odekern1.c rename to GPy/kern/src/todo/odekern1.c diff --git a/GPy/kern/_src/todo/poly.py b/GPy/kern/src/todo/poly.py similarity index 100% rename from GPy/kern/_src/todo/poly.py rename to GPy/kern/src/todo/poly.py diff --git a/GPy/kern/_src/todo/rbf_inv.py b/GPy/kern/src/todo/rbf_inv.py similarity index 100% rename from GPy/kern/_src/todo/rbf_inv.py rename to GPy/kern/src/todo/rbf_inv.py diff --git a/GPy/kern/_src/todo/spline.py b/GPy/kern/src/todo/spline.py similarity index 100% rename from GPy/kern/_src/todo/spline.py rename to GPy/kern/src/todo/spline.py diff --git a/GPy/kern/_src/todo/symmetric.py b/GPy/kern/src/todo/symmetric.py similarity index 100% rename from GPy/kern/_src/todo/symmetric.py rename to GPy/kern/src/todo/symmetric.py diff --git a/GPy/kern/_src/trunclinear.py b/GPy/kern/src/trunclinear.py similarity index 99% rename from GPy/kern/_src/trunclinear.py rename to GPy/kern/src/trunclinear.py index af90c4a5..81d7376f 100644 --- a/GPy/kern/_src/trunclinear.py +++ b/GPy/kern/src/trunclinear.py @@ -7,7 +7,6 @@ from .kern import Kern from ...core.parameterization import Param from ...core.parameterization.transformations import Logexp from ...util.caching import Cache_this -from ...util.config import * class TruncLinear(Kern): """ diff --git a/GPy/models/bayesian_gplvm.py b/GPy/models/bayesian_gplvm.py index 88123227..fd02cb3e 100644 --- a/GPy/models/bayesian_gplvm.py +++ b/GPy/models/bayesian_gplvm.py @@ -99,137 +99,3 @@ class BayesianGPLVM(SparseGP_MPI): self.variational_prior.update_gradients_KL(self.X) self._Xgrad = self.X.gradient.copy() - #super(BayesianGPLVM, self).parameters_changed() - #self._log_marginal_likelihood -= self.variational_prior.KL_divergence(self.X) - - #self.X.mean.gradient, self.X.variance.gradient = self.kern.gradients_qX_expectations(variational_posterior=self.X, Z=self.Z, dL_dpsi0=self.grad_dict['dL_dpsi0'], dL_dpsi1=self.grad_dict['dL_dpsi1'], dL_dpsi2=self.grad_dict['dL_dpsi2']) - - # This is testing code ------------------------- -# i = np.random.randint(self.X.shape[0]) -# X_ = self.X.mean -# which = np.sqrt(((X_ - X_[i:i+1])**2).sum(1)).argsort()>(max(0, self.X.shape[0]-51)) -# _, _, grad_dict = self.inference_method.inference(self.kern, self.X[which], self.Z, self.likelihood, self.Y[which], self.Y_metadata) -# grad = self.kern.gradients_qX_expectations(variational_posterior=self.X[which], Z=self.Z, dL_dpsi0=grad_dict['dL_dpsi0'], dL_dpsi1=grad_dict['dL_dpsi1'], dL_dpsi2=grad_dict['dL_dpsi2']) -# -# self.X.mean.gradient[:] = 0 -# self.X.variance.gradient[:] = 0 -# self.X.mean.gradient[which] = grad[0] -# self.X.variance.gradient[which] = grad[1] - - # update for the KL divergence -# self.variational_prior.update_gradients_KL(self.X, which) - # ----------------------------------------------- - - # update for the KL divergence - #self.variational_prior.update_gradients_KL(self.X) - - def plot_latent(self, labels=None, which_indices=None, - resolution=50, ax=None, marker='o', s=40, - fignum=None, plot_inducing=True, legend=True, - plot_limits=None, - aspect='auto', updates=False, predict_kwargs={}, imshow_kwargs={}): - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_latent(self, labels, which_indices, - resolution, ax, marker, s, - fignum, plot_inducing, legend, - plot_limits, aspect, updates, predict_kwargs, imshow_kwargs) - - def do_test_latents(self, Y): - """ - Compute the latent representation for a set of new points Y - - Notes: - This will only work with a univariate Gaussian likelihood (for now) - """ - N_test = Y.shape[0] - input_dim = self.Z.shape[1] - - means = np.zeros((N_test, input_dim)) - covars = np.zeros((N_test, input_dim)) - - dpsi0 = -0.5 * self.input_dim / self.likelihood.variance - dpsi2 = self.grad_dict['dL_dpsi2'][0][None, :, :] # TODO: this may change if we ignore het. likelihoods - V = Y/self.likelihood.variance - - #compute CPsi1V - #if self.Cpsi1V is None: - # psi1V = np.dot(self.psi1.T, self.likelihood.V) - # tmp, _ = linalg.dtrtrs(self._Lm, np.asfortranarray(psi1V), lower=1, trans=0) - # tmp, _ = linalg.dpotrs(self.LB, tmp, lower=1) - # self.Cpsi1V, _ = linalg.dtrtrs(self._Lm, tmp, lower=1, trans=1) - - dpsi1 = np.dot(self.posterior.woodbury_vector, V.T) - - #start = np.zeros(self.input_dim * 2) - - - from scipy.optimize import minimize - - for n, dpsi1_n in enumerate(dpsi1.T[:, :, None]): - args = (input_dim, self.kern.copy(), self.Z, dpsi0, dpsi1_n.T, dpsi2) - res = minimize(latent_cost_and_grad, jac=True, x0=np.hstack((means[n], covars[n])), args=args, method='BFGS') - xopt = res.x - mu, log_S = xopt.reshape(2, 1, -1) - means[n] = mu[0].copy() - covars[n] = np.exp(log_S[0]).copy() - - X = NormalPosterior(means, covars) - - return X - - def dmu_dX(self, Xnew): - """ - Calculate the gradient of the prediction at Xnew w.r.t Xnew. - """ - dmu_dX = np.zeros_like(Xnew) - for i in range(self.Z.shape[0]): - dmu_dX += self.kern.gradients_X(self.grad_dict['dL_dpsi1'][i:i + 1, :], Xnew, self.Z[i:i + 1, :]) - return dmu_dX - - def dmu_dXnew(self, Xnew): - """ - Individual gradient of prediction at Xnew w.r.t. each sample in Xnew - """ - gradients_X = np.zeros((Xnew.shape[0], self.num_inducing)) - ones = np.ones((1, 1)) - for i in range(self.Z.shape[0]): - gradients_X[:, i] = self.kern.gradients_X(ones, Xnew, self.Z[i:i + 1, :]).sum(-1) - return np.dot(gradients_X, self.grad_dict['dL_dpsi1']) - - def plot_steepest_gradient_map(self, *args, ** kwargs): - """ - See GPy.plotting.matplot_dep.dim_reduction_plots.plot_steepest_gradient_map - """ - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_steepest_gradient_map(self,*args,**kwargs) - - -def latent_cost_and_grad(mu_S, input_dim, kern, Z, dL_dpsi0, dL_dpsi1, dL_dpsi2): - """ - objective function for fitting the latent variables for test points - (negative log-likelihood: should be minimised!) - """ - mu = mu_S[:input_dim][None] - log_S = mu_S[input_dim:][None] - S = np.exp(log_S) - - X = NormalPosterior(mu, S) - - psi0 = kern.psi0(Z, X) - psi1 = kern.psi1(Z, X) - psi2 = kern.psi2(Z, X) - - lik = dL_dpsi0 * psi0.sum() + np.einsum('ij,kj->...', dL_dpsi1, psi1) + np.einsum('ijk,lkj->...', dL_dpsi2, psi2) - 0.5 * np.sum(np.square(mu) + S) + 0.5 * np.sum(log_S) - - dLdmu, dLdS = kern.gradients_qX_expectations(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, X) - dmu = dLdmu - mu - # dS = S0 + S1 + S2 -0.5 + .5/S - dlnS = S * (dLdS - 0.5) + .5 - - return -lik, -np.hstack((dmu.flatten(), dlnS.flatten())) diff --git a/GPy/models/bayesian_gplvm_minibatch.py b/GPy/models/bayesian_gplvm_minibatch.py index 175c3e56..3ef43753 100644 --- a/GPy/models/bayesian_gplvm_minibatch.py +++ b/GPy/models/bayesian_gplvm_minibatch.py @@ -128,115 +128,4 @@ class BayesianGPLVMMiniBatch(SparseGPMiniBatch): d = self.output_dim self._log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(self.X)*self.stochastics.batchsize/d - self._Xgrad = self.X.gradient.copy() - - def plot_latent(self, labels=None, which_indices=None, - resolution=50, ax=None, marker='o', s=40, - fignum=None, plot_inducing=True, legend=True, - plot_limits=None, - aspect='auto', updates=False, predict_kwargs={}, imshow_kwargs={}): - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_latent(self, labels, which_indices, - resolution, ax, marker, s, - fignum, plot_inducing, legend, - plot_limits, aspect, updates, predict_kwargs, imshow_kwargs) - - def do_test_latents(self, Y): - """ - Compute the latent representation for a set of new points Y - - Notes: - This will only work with a univariate Gaussian likelihood (for now) - """ - N_test = Y.shape[0] - input_dim = self.Z.shape[1] - - means = np.zeros((N_test, input_dim)) - covars = np.zeros((N_test, input_dim)) - - dpsi0 = -0.5 * self.input_dim / self.likelihood.variance - dpsi2 = self.grad_dict['dL_dpsi2'][0][None, :, :] # TODO: this may change if we ignore het. likelihoods - V = Y/self.likelihood.variance - - #compute CPsi1V - #if self.Cpsi1V is None: - # psi1V = np.dot(self.psi1.T, self.likelihood.V) - # tmp, _ = linalg.dtrtrs(self._Lm, np.asfortranarray(psi1V), lower=1, trans=0) - # tmp, _ = linalg.dpotrs(self.LB, tmp, lower=1) - # self.Cpsi1V, _ = linalg.dtrtrs(self._Lm, tmp, lower=1, trans=1) - - dpsi1 = np.dot(self.posterior.woodbury_vector, V.T) - - #start = np.zeros(self.input_dim * 2) - - - from scipy.optimize import minimize - - for n, dpsi1_n in enumerate(dpsi1.T[:, :, None]): - args = (input_dim, self.kern.copy(), self.Z, dpsi0, dpsi1_n.T, dpsi2) - res = minimize(latent_cost_and_grad, jac=True, x0=np.hstack((means[n], covars[n])), args=args, method='BFGS') - xopt = res.x - mu, log_S = xopt.reshape(2, 1, -1) - means[n] = mu[0].copy() - covars[n] = np.exp(log_S[0]).copy() - - X = NormalPosterior(means, covars) - - return X - - def dmu_dX(self, Xnew): - """ - Calculate the gradient of the prediction at Xnew w.r.t Xnew. - """ - dmu_dX = np.zeros_like(Xnew) - for i in range(self.Z.shape[0]): - dmu_dX += self.kern.gradients_X(self.grad_dict['dL_dpsi1'][i:i + 1, :], Xnew, self.Z[i:i + 1, :]) - return dmu_dX - - def dmu_dXnew(self, Xnew): - """ - Individual gradient of prediction at Xnew w.r.t. each sample in Xnew - """ - gradients_X = np.zeros((Xnew.shape[0], self.num_inducing)) - ones = np.ones((1, 1)) - for i in range(self.Z.shape[0]): - gradients_X[:, i] = self.kern.gradients_X(ones, Xnew, self.Z[i:i + 1, :]).sum(-1) - return np.dot(gradients_X, self.grad_dict['dL_dpsi1']) - - def plot_steepest_gradient_map(self, *args, ** kwargs): - """ - See GPy.plotting.matplot_dep.dim_reduction_plots.plot_steepest_gradient_map - """ - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_steepest_gradient_map(self,*args,**kwargs) - - -def latent_cost_and_grad(mu_S, input_dim, kern, Z, dL_dpsi0, dL_dpsi1, dL_dpsi2): - """ - objective function for fitting the latent variables for test points - (negative log-likelihood: should be minimised!) - """ - mu = mu_S[:input_dim][None] - log_S = mu_S[input_dim:][None] - S = np.exp(log_S) - - X = NormalPosterior(mu, S) - - psi0 = kern.psi0(Z, X) - psi1 = kern.psi1(Z, X) - psi2 = kern.psi2(Z, X) - - lik = dL_dpsi0 * psi0.sum() + np.einsum('ij,kj->...', dL_dpsi1, psi1) + np.einsum('ijk,lkj->...', dL_dpsi2, psi2) - 0.5 * np.sum(np.square(mu) + S) + 0.5 * np.sum(log_S) - - dLdmu, dLdS = kern.gradients_qX_expectations(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, X) - dmu = dLdmu - mu - # dS = S0 + S1 + S2 -0.5 + .5/S - dlnS = S * (dLdS - 0.5) + .5 - - return -lik, -np.hstack((dmu.flatten(), dlnS.flatten())) + self._Xgrad = self.X.gradient.copy() \ No newline at end of file diff --git a/GPy/models/gp_heteroscedastic_regression.py b/GPy/models/gp_heteroscedastic_regression.py index 63c6352a..7cf0ebf2 100644 --- a/GPy/models/gp_heteroscedastic_regression.py +++ b/GPy/models/gp_heteroscedastic_regression.py @@ -36,5 +36,3 @@ class GPHeteroscedasticRegression(GP): super(GPHeteroscedasticRegression, self).__init__(X,Y,kernel,likelihood, Y_metadata=Y_metadata) - def plot(self,*args): - return NotImplementedError diff --git a/GPy/models/gplvm.py b/GPy/models/gplvm.py index 5bef5be5..6416847c 100644 --- a/GPy/models/gplvm.py +++ b/GPy/models/gplvm.py @@ -6,7 +6,6 @@ import numpy as np from .. import kern from ..core import GP, Param from ..likelihoods import Gaussian -from .. import util class GPLVM(GP): @@ -42,43 +41,4 @@ class GPLVM(GP): def parameters_changed(self): super(GPLVM, self).parameters_changed() - self.X.gradient = self.kern.gradients_X(self.grad_dict['dL_dK'], self.X, None) - - #def jacobian(self,X): - # J = np.zeros((X.shape[0],X.shape[1],self.output_dim)) - # for i in range(self.output_dim): - # J[:,:,i] = self.kern.gradients_X(self.posterior.woodbury_vector[:,i:i+1], X, self.X) - # return J - - #def magnification(self,X): - # target=np.zeros(X.shape[0]) - # #J = np.zeros((X.shape[0],X.shape[1],self.output_dim)) - ## J = self.jacobian(X) - # for i in range(X.shape[0]): - # target[i]=np.sqrt(np.linalg.det(np.dot(J[i,:,:],np.transpose(J[i,:,:])))) - # return target - - def plot(self): - assert self.Y.shape[1] == 2, "too high dimensional to plot. Try plot_latent" - from matplotlib import pyplot as plt - plt.scatter(self.Y[:, 0], - self.Y[:, 1], - 40, self.X[:, 0].copy(), - linewidth=0, cmap=plt.cm.jet) - Xnew = np.linspace(self.X.min(), self.X.max(), 200)[:, None] - mu, _ = self.predict(Xnew) - plt.plot(mu[:, 0], mu[:, 1], 'k', linewidth=1.5) - - def plot_latent(self, labels=None, which_indices=None, - resolution=50, ax=None, marker='o', s=40, - fignum=None, legend=True, - plot_limits=None, - aspect='auto', updates=False, **kwargs): - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_latent(self, labels, which_indices, - resolution, ax, marker, s, - fignum, False, legend, - plot_limits, aspect, updates, **kwargs) + self.X.gradient = self.kern.gradients_X(self.grad_dict['dL_dK'], self.X, None) \ No newline at end of file diff --git a/GPy/models/ss_gplvm.py b/GPy/models/ss_gplvm.py index 3e2aa552..4ccf58ac 100644 --- a/GPy/models/ss_gplvm.py +++ b/GPy/models/ss_gplvm.py @@ -9,7 +9,7 @@ from ..core.parameterization import Param from ..likelihoods import Gaussian from ..core.parameterization.variational import SpikeAndSlabPrior, SpikeAndSlabPosterior,VariationalPrior from ..inference.latent_function_inference.var_dtc_parallel import update_gradients, VarDTC_minibatch -from ..kern._src.psi_comp.ssrbf_psi_gpucomp import PSICOMP_SSRBF_GPU +from ..kern.src.psi_comp.ssrbf_psi_gpucomp import PSICOMP_SSRBF_GPU class IBPPosterior(SpikeAndSlabPosterior): ''' @@ -190,12 +190,4 @@ class SSGPLVM(SparseGP_MPI): if self.kern.ARD: return self.kern.input_sensitivity() else: - return self.variational_prior.pi - - def plot_latent(self, plot_inducing=True, *args, **kwargs): - import sys - assert "matplotlib" in sys.modules, "matplotlib package has not been imported." - from ..plotting.matplot_dep import dim_reduction_plots - - return dim_reduction_plots.plot_latent(self, plot_inducing=plot_inducing, *args, **kwargs) - + return self.variational_prior.pi \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/Tango.py b/GPy/plotting/Tango.py similarity index 69% rename from GPy/plotting/matplot_dep/Tango.py rename to GPy/plotting/Tango.py index 5c004519..eb943962 100644 --- a/GPy/plotting/matplot_dep/Tango.py +++ b/GPy/plotting/Tango.py @@ -1,30 +1,6 @@ # Copyright (c) 2012, GPy authors (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) - -import matplotlib as mpl -from matplotlib import pyplot as pb -import sys -#sys.path.append('/home/james/mlprojects/sitran_cluster/') -#from switch_pylab_backend import * - - -#this stuff isn;t really Tango related: maybe it could be moved out? TODO -def removeRightTicks(ax=None): - ax = ax or pb.gca() - for i, line in enumerate(ax.get_yticklines()): - if i%2 == 1: # odd indices - line.set_visible(False) -def removeUpperTicks(ax=None): - ax = ax or pb.gca() - for i, line in enumerate(ax.get_xticklines()): - if i%2 == 1: # odd indices - line.set_visible(False) -def fewerXticks(ax=None,divideby=2): - ax = ax or pb.gca() - ax.set_xticks(ax.get_xticks()[::divideby]) - - colorsHex = {\ "Aluminium6":"#2e3436",\ "Aluminium5":"#555753",\ @@ -83,32 +59,6 @@ def reset(): while not lightList[0]==colorsHex['lightBlue']: lightList.append(lightList.pop(0)) -def setLightFigures(): - mpl.rcParams['axes.edgecolor']=colorsHex['Aluminium6'] - mpl.rcParams['axes.facecolor']=colorsHex['Aluminium2'] - mpl.rcParams['axes.labelcolor']=colorsHex['Aluminium6'] - mpl.rcParams['figure.edgecolor']=colorsHex['Aluminium6'] - mpl.rcParams['figure.facecolor']=colorsHex['Aluminium2'] - mpl.rcParams['grid.color']=colorsHex['Aluminium6'] - mpl.rcParams['savefig.edgecolor']=colorsHex['Aluminium2'] - mpl.rcParams['savefig.facecolor']=colorsHex['Aluminium2'] - mpl.rcParams['text.color']=colorsHex['Aluminium6'] - mpl.rcParams['xtick.color']=colorsHex['Aluminium6'] - mpl.rcParams['ytick.color']=colorsHex['Aluminium6'] - -def setDarkFigures(): - mpl.rcParams['axes.edgecolor']=colorsHex['Aluminium2'] - mpl.rcParams['axes.facecolor']=colorsHex['Aluminium6'] - mpl.rcParams['axes.labelcolor']=colorsHex['Aluminium2'] - mpl.rcParams['figure.edgecolor']=colorsHex['Aluminium2'] - mpl.rcParams['figure.facecolor']=colorsHex['Aluminium6'] - mpl.rcParams['grid.color']=colorsHex['Aluminium2'] - mpl.rcParams['savefig.edgecolor']=colorsHex['Aluminium6'] - mpl.rcParams['savefig.facecolor']=colorsHex['Aluminium6'] - mpl.rcParams['text.color']=colorsHex['Aluminium2'] - mpl.rcParams['xtick.color']=colorsHex['Aluminium2'] - mpl.rcParams['ytick.color']=colorsHex['Aluminium2'] - def hex2rgb(hexcolor): hexcolor = [hexcolor[1+2*i:1+2*(i+1)] for i in range(3)] r,g,b = [int(n,16) for n in hexcolor] @@ -154,13 +104,4 @@ cdict_Alu = {'red' :((0./5,colorsRGB['Aluminium1'][0]/256.,colorsRGB['Aluminium1 (2./5,colorsRGB['Aluminium3'][2]/256.,colorsRGB['Aluminium3'][2]/256.), (3./5,colorsRGB['Aluminium4'][2]/256.,colorsRGB['Aluminium4'][2]/256.), (4./5,colorsRGB['Aluminium5'][2]/256.,colorsRGB['Aluminium5'][2]/256.), - (5./5,colorsRGB['Aluminium6'][2]/256.,colorsRGB['Aluminium6'][2]/256.))} -# cmap_Alu = mpl.colors.LinearSegmentedColormap('TangoAluminium',cdict_Alu,256) -# cmap_BGR = mpl.colors.LinearSegmentedColormap('TangoRedBlue',cdict_BGR,256) -# cmap_RB = mpl.colors.LinearSegmentedColormap('TangoRedBlue',cdict_RB,256) -if __name__=='__main__': - from matplotlib import pyplot as pb - pb.figure() - pb.pcolor(pb.rand(10,10),cmap=cmap_RB) - pb.colorbar() - pb.show() + (5./5,colorsRGB['Aluminium6'][2]/256.,colorsRGB['Aluminium6'][2]/256.))} \ No newline at end of file diff --git a/GPy/plotting/__init__.py b/GPy/plotting/__init__.py index d89369ad..28c05cef 100644 --- a/GPy/plotting/__init__.py +++ b/GPy/plotting/__init__.py @@ -1,12 +1,96 @@ # Copyright (c) 2014, GPy authors (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) -try: - import matplotlib - from . import matplot_dep -except (ImportError, NameError): - # Matplotlib not available - import warnings - warnings.warn(ImportWarning("Matplotlib not available, install newest version of Matplotlib for plotting")) - #sys.modules['matplotlib'] = - #sys.modules[__name__+'.matplot_dep'] = ImportWarning("Matplotlib not available, install newest version of Matplotlib for plotting") +current_lib = [None] + +def change_plotting_library(lib): + try: + #=========================================================================== + # Load in your plotting library here and + # save it under the name plotting_library! + # This is hooking the library in + # for the usage in GPy: + if lib == 'matplotlib': + import matplotlib + from .matplot_dep.plot_definitions import MatplotlibPlots + current_lib[0] = MatplotlibPlots() + if lib == 'plotly': + import plotly + from .plotly_dep.plot_definitions import PlotlyPlots + current_lib[0] = PlotlyPlots() + if lib == 'none': + current_lib[0] = None + #=========================================================================== + except (ImportError, NameError): + config.set('plotting', 'library', 'none') + import warnings + warnings.warn(ImportWarning("{} not available, install newest version of {} for plotting".format(lib, lib))) + +from ..util.config import config +lib = config.get('plotting', 'library') +change_plotting_library(lib) + +def plotting_library(): + return current_lib[0] + +def show(figure, **kwargs): + """ + Show the specific plotting library figure, returned by + add_to_canvas(). + + kwargs are the plotting library specific options + for showing/drawing a figure. + """ + return plotting_library().show_canvas(figure, **kwargs) + +if config.get('plotting', 'library') is not 'none': + # Inject the plots into classes here: + + # Already converted to new style: + from . import gpy_plot + + from ..core import GP + GP.plot_data = gpy_plot.data_plots.plot_data + GP.plot_data_error = gpy_plot.data_plots.plot_data_error + GP.plot_errorbars_trainset = gpy_plot.data_plots.plot_errorbars_trainset + GP.plot_mean = gpy_plot.gp_plots.plot_mean + GP.plot_confidence = gpy_plot.gp_plots.plot_confidence + GP.plot_density = gpy_plot.gp_plots.plot_density + GP.plot_samples = gpy_plot.gp_plots.plot_samples + GP.plot = gpy_plot.gp_plots.plot + GP.plot_f = gpy_plot.gp_plots.plot_f + GP.plot_magnification = gpy_plot.latent_plots.plot_magnification + + from ..core import SparseGP + SparseGP.plot_inducing = gpy_plot.data_plots.plot_inducing + + from ..models import GPLVM, BayesianGPLVM, bayesian_gplvm_minibatch, SSGPLVM, SSMRD + GPLVM.plot_latent = gpy_plot.latent_plots.plot_latent + GPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter + GPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing + GPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map + BayesianGPLVM.plot_latent = gpy_plot.latent_plots.plot_latent + BayesianGPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter + BayesianGPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing + BayesianGPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map + bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_latent = gpy_plot.latent_plots.plot_latent + bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter + bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing + bayesian_gplvm_minibatch.BayesianGPLVMMiniBatch.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map + SSGPLVM.plot_latent = gpy_plot.latent_plots.plot_latent + SSGPLVM.plot_scatter = gpy_plot.latent_plots.plot_latent_scatter + SSGPLVM.plot_inducing = gpy_plot.latent_plots.plot_latent_inducing + SSGPLVM.plot_steepest_gradient_map = gpy_plot.latent_plots.plot_steepest_gradient_map + + from ..kern import Kern + Kern.plot_covariance = gpy_plot.kernel_plots.plot_covariance + def deprecate_plot(self, *args, **kwargs): + import warnings + warnings.warn(DeprecationWarning('Kern.plot is being deprecated and will not be available in the 1.0 release. Use Kern.plot_covariance instead')) + return self.plot_covariance(*args, **kwargs) + Kern.plot = deprecate_plot + Kern.plot_ARD = gpy_plot.kernel_plots.plot_ARD + + from ..inference.optimization import Optimizer + Optimizer.plot = gpy_plot.inference_plots.plot_optimizer + # Variational plot! diff --git a/GPy/plotting/abstract_plotting_library.py b/GPy/plotting/abstract_plotting_library.py new file mode 100644 index 00000000..64061b99 --- /dev/null +++ b/GPy/plotting/abstract_plotting_library.py @@ -0,0 +1,280 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy.plotting.abstract_plotting_library nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== + +#=============================================================================== +# Make sure that the necessary files and functions are +# defined in the plotting library: +class AbstractPlottingLibrary(object): + def __init__(self): + """ + Set the defaults dictionary in the _defaults variable: + + E.g. for matplotlib we define a file defaults.py and + set the dictionary of it here: + + from . import defaults + _defaults = defaults.__dict__ + """ + self._defaults = {} + self.__defaults = None + + @property + def defaults(self): + #=============================================================================== + if self.__defaults is None: + from collections import defaultdict + class defaultdict(defaultdict): + def __getattr__(self, *args, **kwargs): + return defaultdict.__getitem__(self, *args, **kwargs) + self.__defaults = defaultdict(dict, self._defaults) + return self.__defaults + #=============================================================================== + + def figure(self, nrows, ncols, **kwargs): + """ + Get a new figure with nrows and ncolumns subplots. + Does not initialize the canvases yet. + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def new_canvas(self, figure=None, col=1, row=1, projection='2d', xlabel=None, ylabel=None, zlabel=None, title=None, xlim=None, ylim=None, zlim=None, **kwargs): + """ + Return a canvas, kwargupdate for your plotting library. + + if figure is not None, create a canvas in the figure + at subplot position (col, row). + + This method does two things, it creates an empty canvas + and updates the kwargs (deletes the unnecessary kwargs) + for further usage in normal plotting. + + the kwargs are plotting library specific kwargs! + + :param {'2d'|'3d'} projection: The projection to use. + + E.g. in matplotlib this means it deletes references to ax, as + plotting is done on the axis itself and is not a kwarg. + + :param xlabel: the label to put on the xaxis + :param ylabel: the label to put on the yaxis + :param zlabel: the label to put on the zaxis (if plotting in 3d) + :param title: the title of the plot + :param legend: if True, plot a legend, if int make legend rows in the legend + :param (float, float) xlim: the limits for the xaxis + :param (float, float) ylim: the limits for the yaxis + :param (float, float) zlim: the limits for the zaxis (if plotting in 3d) + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def add_to_canvas(self, canvas, plots, legend=True, title=None, **kwargs): + """ + Add plots is a dictionary with the plots as the + items or a list of plots as items to canvas. + + The kwargs are plotting library specific kwargs! + + E.g. in matplotlib this does not have to do anything to add stuff, but + we set the legend and title. + + !This function returns the updated canvas! + + :param title: the title of the plot + :param legend: whether to plot a legend or not + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def show_canvas(self, canvas, **kwargs): + """ + Draw/Plot the canvas given. + """ + raise NotImplementedError + + def plot(self, cavas, X, Y, Z=None, color=None, label=None, **kwargs): + """ + Make a line plot from for Y on X (Y = f(X)) on the canvas. + If Z is not None, plot in 3d! + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def plot_axis_lines(self, ax, X, color=None, label=None, **kwargs): + """ + Plot lines at the bottom (lower boundary of yaxis) of the axis at input location X. + + If X is two dimensional, plot in 3d and connect the axis lines to the bottom of the Z axis. + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def surface(self, canvas, X, Y, Z, color=None, label=None, **kwargs): + """ + Plot a surface for 3d plotting for the inputs (X, Y, Z). + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def scatter(self, canvas, X, Y, Z=None, color=None, vmin=None, vmax=None, label=None, **kwargs): + """ + Make a scatter plot between X and Y on the canvas given. + + the kwargs are plotting library specific kwargs! + + :param canvas: the plotting librarys specific canvas to plot on. + :param array-like X: the inputs to plot. + :param array-like Y: the outputs to plot. + :param array-like Z: the Z level to plot (if plotting 3d). + :param array-like c: the colorlevel for each point. + :param float vmin: minimum colorscale + :param float vmax: maximum colorscale + :param kwargs: the specific kwargs for your plotting library + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def barplot(self, canvas, x, height, width=0.8, bottom=0, color=None, label=None, **kwargs): + """ + Plot vertical bar plot centered at x with height + and width of bars. The y level is at bottom. + + the kwargs are plotting library specific kwargs! + + :param array-like x: the center points of the bars + :param array-like height: the height of the bars + :param array-like width: the width of the bars + :param array-like bottom: the start y level of the bars + :param kwargs: kwargs for the specific library you are using. + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def xerrorbar(self, canvas, X, Y, error, color=None, label=None, **kwargs): + """ + Make an errorbar along the xaxis for points at (X,Y) on the canvas. + if error is two dimensional, the lower error is error[:,0] and + the upper error is error[:,1] + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def yerrorbar(self, canvas, X, Y, error, color=None, label=None, **kwargs): + """ + Make errorbars along the yaxis on the canvas given. + if error is two dimensional, the lower error is error[0, :] and + the upper error is error[1, :] + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def imshow(self, canvas, X, extent=None, label=None, vmin=None, vmax=None, **kwargs): + """ + Show the image stored in X on the canvas. + + The origin of the image show is (0,0), such that X[0,0] gets plotted at [0,0] of the image! + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def imshow_interact(self, canvas, plot_function, extent=None, label=None, vmin=None, vmax=None, **kwargs): + """ + This function is optional! + + Create an imshow controller to stream + the image returned by the plot_function. There is an imshow controller written for + mmatplotlib, which updates the imshow on changes in axis. + + The origin of the image show is (0,0), such that X[0,0] gets plotted at [0,0] of the image! + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def annotation_heatmap(self, canvas, X, annotation, extent, label=None, **kwargs): + """ + Plot an annotation heatmap. That is like an imshow, but + put the text of the annotation inside the cells of the heatmap (centered). + + :param canvas: the canvas to plot on + :param array-like annotation: the annotation labels for the heatmap + :param [horizontal_min,horizontal_max,vertical_min,vertical_max] extent: the extent of where to place the heatmap + :param str label: the label for the heatmap + :return: a list of both the heatmap and annotation plots [heatmap, annotation], or the interactive update object (alone) + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def annotation_heatmap_interact(self, canvas, plot_function, extent, label=None, resolution=15, **kwargs): + """ + if plot_function is not None, return an interactive updated + heatmap, which updates on axis events, so that one can zoom in + and out and the heatmap gets updated. See the matplotlib implementation + in matplot_dep.controllers. + + the plot_function returns a pair (X, annotation) to plot, when called with + a new input X (which would be the grid, which is visible on the plot + right now) + + :param canvas: the canvas to plot on + :param array-like annotation: the annotation labels for the heatmap + :param [horizontal_min,horizontal_max,vertical_min,vertical_max] extent: the extent of where to place the heatmap + :param str label: the label for the heatmap + :return: a list of both the heatmap and annotation plots [heatmap, annotation], or the interactive update object (alone) + :param plot_function: the function, which generates new data for given input locations X + :param int resolution: the resolution of the interactive plot redraw - this is only needed when giving a plot_function + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def contour(self, canvas, X, Y, C, Z=None, color=None, label=None, **kwargs): + """ + Make a contour plot at (X, Y) with heights/colors stored in C on the canvas. + + if Z is not None: make 3d contour plot at (X, Y, Z) with heights/colors stored in C on the canvas. + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def fill_between(self, canvas, X, lower, upper, color=None, label=None, **kwargs): + """ + Fill along the xaxis between lower and upper. + + the kwargs are plotting library specific kwargs! + """ + raise NotImplementedError("Implement all plot functions in AbstractPlottingLibrary in order to use your own plotting library") + + def fill_gradient(self, canvas, X, percentiles, color=None, label=None, **kwargs): + """ + Plot a gradient (in alpha values) for the given percentiles. + + the kwargs are plotting library specific kwargs! + """ + print("fill_gradient not implemented in this backend.") diff --git a/GPy/plotting/gpy_plot/__init__.py b/GPy/plotting/gpy_plot/__init__.py new file mode 100644 index 00000000..d63f25f6 --- /dev/null +++ b/GPy/plotting/gpy_plot/__init__.py @@ -0,0 +1,2 @@ +from .. import plotting_library +from . import data_plots, gp_plots, latent_plots, kernel_plots, plot_util, inference_plots diff --git a/GPy/plotting/gpy_plot/data_plots.py b/GPy/plotting/gpy_plot/data_plots.py new file mode 100644 index 00000000..a24a67ab --- /dev/null +++ b/GPy/plotting/gpy_plot/data_plots.py @@ -0,0 +1,277 @@ +#=============================================================================== +# Copyright (c) 2012-2015, GPy authors (see AUTHORS.txt). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== +import numpy as np +from . import plotting_library as pl +#from .. import gpy_plot +from .plot_util import get_x_y_var, get_free_dims, get_which_data_ycols,\ + get_which_data_rows, update_not_existing_kwargs, helper_predict_with_model + +def plot_data(self, which_data_rows='all', + which_data_ycols='all', visible_dims=None, + projection='2d', label=None, **plot_kwargs): + """ + Plot the training data + - For higher dimensions than two, use fixed_inputs to plot the data points with some of the inputs fixed. + + Can plot only part of the data + using which_data_rows and which_data_ycols. + + :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 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 visible_dims: an array specifying the input dimensions to plot (maximum two) + :type visible_dims: a numpy array + :param {'2d','3d'} projection: whether to plot in 2d or 3d. This only applies when plotting two dimensional inputs! + :param str label: the label for the plot + :param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using + + :returns list: of plots created. + """ + canvas, plot_kwargs = pl().new_canvas(projection=projection, **plot_kwargs) + plots = _plot_data(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, label, **plot_kwargs) + return pl().add_to_canvas(canvas, plots) + +def _plot_data(self, canvas, which_data_rows='all', + which_data_ycols='all', visible_dims=None, + projection='2d', label=None, **plot_kwargs): + ycols = get_which_data_ycols(self, which_data_ycols) + rows = get_which_data_rows(self, which_data_rows) + + X, _, Y = get_x_y_var(self) + free_dims = get_free_dims(self, visible_dims, None) + + plots = {} + plots['dataplot'] = [] + + #one dimensional plotting + if len(free_dims) == 1: + for d in ycols: + update_not_existing_kwargs(plot_kwargs, pl().defaults.data_1d) # @UndefinedVariable + plots['dataplot'].append(pl().scatter(canvas, X[rows, free_dims], Y[rows, d], label=label, **plot_kwargs)) + #2D plotting + elif len(free_dims) == 2: + if projection=='2d': + for d in ycols: + update_not_existing_kwargs(plot_kwargs, pl().defaults.data_2d) # @UndefinedVariable + plots['dataplot'].append(pl().scatter(canvas, X[rows, free_dims[0]], X[rows, free_dims[1]], + color=Y[rows, d], label=label, **plot_kwargs)) + else: + for d in ycols: + update_not_existing_kwargs(plot_kwargs, pl().defaults.data_2d) # @UndefinedVariable + plots['dataplot'].append(pl().scatter(canvas, X[rows, free_dims[0]], X[rows, free_dims[1]], + Z=Y[rows, d], color=Y[rows, d], label=label, **plot_kwargs)) + elif len(free_dims) == 0: + pass #Nothing to plot! + else: + raise NotImplementedError("Cannot plot in more then two dimensions") + return plots + +def plot_data_error(self, which_data_rows='all', + which_data_ycols='all', visible_dims=None, + projection='2d', label=None, **error_kwargs): + """ + Plot the training data input error. + + For higher dimensions than two, use fixed_inputs to plot the data points with some of the inputs fixed. + + Can plot only part of the data + using which_data_rows and which_data_ycols. + + :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 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 visible_dims: an array specifying the input dimensions to plot (maximum two) + :type visible_dims: a numpy array + :param {'2d','3d'} projection: whether to plot in 2d or 3d. This only applies when plotting two dimensional inputs! + :param dict error_kwargs: kwargs for the error plot for the plotting library you are using + :param str label: the label for the plot + :param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using + + :returns list: of plots created. + """ + canvas, error_kwargs = pl().new_canvas(projection=projection, **error_kwargs) + plots = _plot_data_error(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, label, **error_kwargs) + return pl().add_to_canvas(canvas, plots) + +def _plot_data_error(self, canvas, which_data_rows='all', + which_data_ycols='all', visible_dims=None, + projection='2d', label=None, **error_kwargs): + ycols = get_which_data_ycols(self, which_data_ycols) + rows = get_which_data_rows(self, which_data_rows) + + X, X_variance, Y = get_x_y_var(self) + free_dims = get_free_dims(self, visible_dims, None) + + plots = {} + + if X_variance is not None: + plots['input_error'] = [] + #one dimensional plotting + if len(free_dims) == 1: + for d in ycols: + update_not_existing_kwargs(error_kwargs, pl().defaults.xerrorbar) + plots['input_error'].append(pl().xerrorbar(canvas, X[rows, free_dims].flatten(), Y[rows, d].flatten(), + 2 * np.sqrt(X_variance[rows, free_dims].flatten()), label=label, + **error_kwargs)) + #2D plotting + elif len(free_dims) == 2: + update_not_existing_kwargs(error_kwargs, pl().defaults.xerrorbar) # @UndefinedVariable + plots['input_error'].append(pl().xerrorbar(canvas, X[rows, free_dims[0]].flatten(), X[rows, free_dims[1]].flatten(), + 2 * np.sqrt(X_variance[rows, free_dims[0]].flatten()), label=label, + **error_kwargs)) + plots['input_error'].append(pl().yerrorbar(canvas, X[rows, free_dims[0]].flatten(), X[rows, free_dims[1]].flatten(), + 2 * np.sqrt(X_variance[rows, free_dims[1]].flatten()), label=label, + **error_kwargs)) + elif len(free_dims) == 0: + pass #Nothing to plot! + else: + raise NotImplementedError("Cannot plot in more then two dimensions") + + return plots + +def plot_inducing(self, visible_dims=None, projection='2d', label='inducing', **plot_kwargs): + """ + Plot the inducing inputs of a sparse gp model + + :param array-like visible_dims: an array specifying the input dimensions to plot (maximum two) + :param kwargs plot_kwargs: keyword arguments for the plotting library + """ + canvas, kwargs = pl().new_canvas(projection=projection, **plot_kwargs) + plots = _plot_inducing(self, canvas, visible_dims, projection, label, **kwargs) + return pl().add_to_canvas(canvas, plots, legend=label is not None) + +def _plot_inducing(self, canvas, visible_dims, projection, label, **plot_kwargs): + if visible_dims is None: + sig_dims = self.get_most_significant_input_dimensions() + visible_dims = [i for i in sig_dims if i is not None] + free_dims = get_free_dims(self, visible_dims, None) + + Z = self.Z[:, free_dims] + plots = {} + + #one dimensional plotting + if len(free_dims) == 1: + update_not_existing_kwargs(plot_kwargs, pl().defaults.inducing_1d) # @UndefinedVariable + plots['inducing'] = pl().plot_axis_lines(canvas, Z[:, free_dims], label=label, **plot_kwargs) + #2D plotting + elif len(free_dims) == 2 and projection == '3d': + update_not_existing_kwargs(plot_kwargs, pl().defaults.inducing_3d) # @UndefinedVariable + plots['inducing'] = pl().plot_axis_lines(canvas, Z[:, free_dims], label=label, **plot_kwargs) + elif len(free_dims) == 2: + update_not_existing_kwargs(plot_kwargs, pl().defaults.inducing_2d) # @UndefinedVariable + plots['inducing'] = pl().scatter(canvas, Z[:, free_dims[0]], Z[:, free_dims[1]], + label=label, **plot_kwargs) + elif len(free_dims) == 0: + pass #Nothing to plot! + else: + raise NotImplementedError("Cannot plot in more then two dimensions") + return plots + +def plot_errorbars_trainset(self, which_data_rows='all', + which_data_ycols='all', fixed_inputs=None, + plot_raw=False, apply_link=False, label=None, projection='2d', + predict_kw=None, **plot_kwargs): + """ + Plot the errorbars of the GP likelihood on the training data. + These are the errorbars after the appropriate + approximations according to the likelihood are done. + + This also works for heteroscedastic likelihoods. + + Give the Y_metadata in the predict_kw if you need it. + + :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 which_data_ycols: when the data has several columns (independant outputs), only plot these + :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 dict predict_kwargs: kwargs for the prediction used to predict the right quantiles. + :param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using + """ + canvas, kwargs = pl().new_canvas(projection=projection, **plot_kwargs) + plots = _plot_errorbars_trainset(self, canvas, which_data_rows, which_data_ycols, + fixed_inputs, plot_raw, apply_link, label, projection, predict_kw, **kwargs) + return pl().add_to_canvas(canvas, plots) + +def _plot_errorbars_trainset(self, canvas, + which_data_rows='all', which_data_ycols='all', + fixed_inputs=None, + plot_raw=False, apply_link=False, + label=None, projection='2d', predict_kw=None, **plot_kwargs): + + ycols = get_which_data_ycols(self, which_data_ycols) + rows = get_which_data_rows(self, which_data_rows) + + X, _, Y = get_x_y_var(self) + + if fixed_inputs is None: + fixed_inputs = [] + free_dims = get_free_dims(self, None, fixed_inputs) + + Xgrid = X.copy() + for i, v in fixed_inputs: + Xgrid[:, i] = v + + plots = [] + + if len(free_dims)<=2 and projection=='2d': + update_not_existing_kwargs(plot_kwargs, pl().defaults.yerrorbar) + if predict_kw is None: + predict_kw = {} + if 'Y_metadata' not in predict_kw: + predict_kw['Y_metadata'] = self.Y_metadata or {} + mu, percs, _ = helper_predict_with_model(self, Xgrid, plot_raw, + apply_link, (2.5, 97.5), + ycols, predict_kw) + if len(free_dims)==1: + for d in ycols: + plots.append(pl().yerrorbar(canvas, X[rows,free_dims[0]], mu[rows,d], + np.vstack([mu[rows, d] - percs[0][rows, d], percs[1][rows, d] - mu[rows,d]]), + label=label, + **plot_kwargs)) +# elif len(free_dims) == 2: +# for d in ycols: +# plots.append(pl().yerrorbar(canvas, X[rows,free_dims[0]], X[rows,free_dims[1]], +# np.vstack([mu[rows, d] - percs[0][rows, d], percs[1][rows, d] - mu[rows,d]]), +# #color=Y[rows,d], +# label=label, +# **plot_kwargs)) +# plots.append(pl().xerrorbar(canvas, X[rows,free_dims[0]], X[rows,free_dims[1]], +# np.vstack([mu[rows, d] - percs[0][rows, d], percs[1][rows, d] - mu[rows,d]]), +# #color=Y[rows,d], +# label=label, +# **plot_kwargs)) + else: + raise NotImplementedError("Cannot plot in more then one dimensions, or 3d") + return dict(yerrorbars=plots) + + diff --git a/GPy/plotting/gpy_plot/gp_plots.py b/GPy/plotting/gpy_plot/gp_plots.py new file mode 100644 index 00000000..da92748d --- /dev/null +++ b/GPy/plotting/gpy_plot/gp_plots.py @@ -0,0 +1,415 @@ +#=============================================================================== +# Copyright (c) 2012-2015, GPy authors (see AUTHORS.txt). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== + +import numpy as np + +from . import plotting_library as pl +from .plot_util import helper_for_plot_data, update_not_existing_kwargs, \ + helper_predict_with_model, get_which_data_ycols, get_x_y_var +from .data_plots import _plot_data, _plot_inducing, _plot_data_error + +def plot_mean(self, plot_limits=None, fixed_inputs=None, + resolution=None, plot_raw=False, + apply_link=False, visible_dims=None, + which_data_ycols='all', + levels=20, projection='2d', + label='gp mean', + predict_kw=None, + **kwargs): + """ + Plot the mean of the 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. + + + + :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 [defaults are 1D:200, 2D:50] + :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 array-like which_data_ycols: which columns of y to plot (array-like or list of ints) + :param int levels: for 2D plotting, the number of contour levels to use is + :param {'2d','3d'} projection: whether to plot in 2d or 3d. This only applies when plotting two dimensional inputs! + :param str label: the label for the plot. + :param dict predict_kw: the keyword arguments for the prediction. If you want to plot a specific kernel give dict(kern=) in here + """ + canvas, kwargs = pl().new_canvas(projection=projection, **kwargs) + X = get_x_y_var(self)[0] + helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) + helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, + apply_link, None, + get_which_data_ycols(self, which_data_ycols), + predict_kw) + plots = _plot_mean(self, canvas, helper_data, helper_prediction, + levels, projection, label, **kwargs) + return pl().add_to_canvas(canvas, plots) + +def _plot_mean(self, canvas, helper_data, helper_prediction, + levels=20, projection='2d', label=None, + **kwargs): + + _, free_dims, Xgrid, x, y, _, _, resolution = helper_data + if len(free_dims)<=2: + mu, _, _ = helper_prediction + if len(free_dims)==1: + # 1D plotting: + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_1d) # @UndefinedVariable + plots = dict(gpmean=[pl().plot(canvas, Xgrid[:, free_dims], mu, label=label, **kwargs)]) + else: + if projection == '2d': + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable + plots = dict(gpmean=[pl().contour(canvas, x[:,0], y[0,:], + mu.reshape(resolution, resolution), + levels=levels, label=label, **kwargs)]) + elif projection == '3d': + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable + plots = dict(gpmean=[pl().surface(canvas, x, y, + mu.reshape(resolution, resolution), + label=label, + **kwargs)]) + elif len(free_dims)==0: + pass # Nothing to plot! + else: + raise RuntimeError('Cannot plot mean in more then 2 input dimensions') + return plots + +def plot_confidence(self, lower=2.5, upper=97.5, plot_limits=None, fixed_inputs=None, + resolution=None, plot_raw=False, + apply_link=False, visible_dims=None, + which_data_ycols='all', label='gp confidence', + predict_kw=None, + **kwargs): + """ + Plot the confidence interval between the percentiles lower and upper. + E.g. the 95% confidence interval is $2.5, 97.5$. + Note: Only implemented for one dimension! + + 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. + + + :param float lower: the lower percentile to plot + :param float upper: the upper percentile to plot + :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 array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) + :param array-like which_data_ycols: which columns of the output y (!) to plot (array-like or list of ints) + :param dict predict_kw: the keyword arguments for the prediction. If you want to plot a specific kernel give dict(kern=) in here + """ + canvas, kwargs = pl().new_canvas(**kwargs) + ycols = get_which_data_ycols(self, which_data_ycols) + X = get_x_y_var(self)[0] + helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) + helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, apply_link, + (lower, upper), + ycols, predict_kw) + plots = _plot_confidence(self, canvas, helper_data, helper_prediction, label, **kwargs) + return pl().add_to_canvas(canvas, plots, legend=label is not None) + +def _plot_confidence(self, canvas, helper_data, helper_prediction, label, **kwargs): + _, free_dims, Xgrid, _, _, _, _, _ = helper_data + update_not_existing_kwargs(kwargs, pl().defaults.confidence_interval) # @UndefinedVariable + if len(free_dims)<=1: + if len(free_dims)==1: + percs = helper_prediction[1] + fills = [] + for d in range(helper_prediction[0].shape[1]): + fills.append(pl().fill_between(canvas, Xgrid[:,free_dims[0]], percs[0][:,d], percs[1][:,d], label=label, **kwargs)) + return dict(gpconfidence=fills) + else: + pass #Nothing to plot! + else: + raise RuntimeError('Can only plot confidence interval in one input dimension') + + +def plot_samples(self, plot_limits=None, fixed_inputs=None, + resolution=None, plot_raw=True, + apply_link=False, visible_dims=None, + which_data_ycols='all', + samples=3, projection='2d', label='gp_samples', + predict_kw=None, + **kwargs): + """ + Plot the mean of the 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. + + + + :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 [defaults are 1D:200, 2D:50] + :param bool plot_raw: plot the latent function (usually denoted f) only? This is usually what you want! + :param bool apply_link: whether to apply the link function of the GP to the raw prediction. + :param array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) + :param array-like which_data_ycols: which columns of y to plot (array-like or list of ints) + :param dict predict_kw: the keyword arguments for the prediction. If you want to plot a specific kernel give dict(kern=) in here + :param int levels: for 2D plotting, the number of contour levels to use is + """ + canvas, kwargs = pl().new_canvas(projection=projection, **kwargs) + ycols = get_which_data_ycols(self, which_data_ycols) + X = get_x_y_var(self)[0] + helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) + helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, apply_link, + None, + ycols, predict_kw, samples) + plots = _plot_samples(self, canvas, helper_data, helper_prediction, + projection, label, **kwargs) + return pl().add_to_canvas(canvas, plots) + +def _plot_samples(self, canvas, helper_data, helper_prediction, projection, + label, **kwargs): + _, free_dims, Xgrid, x, y, _, _, resolution = helper_data + samples = helper_prediction[2] + + if len(free_dims)<=2: + if len(free_dims)==1: + # 1D plotting: + update_not_existing_kwargs(kwargs, pl().defaults.samples_1d) # @UndefinedVariable + plots = [pl().plot(canvas, Xgrid[:, free_dims], samples[:, s], label=label if s==0 else None, **kwargs) for s in range(samples.shape[-1])] + elif len(free_dims)==2 and projection=='3d': + update_not_existing_kwargs(kwargs, pl().defaults.samples_3d) # @UndefinedVariable + plots = [pl().surface(canvas, x, y, samples[:, s].reshape(resolution, resolution), **kwargs) for s in range(samples.shape[-1])] + else: + pass # Nothing to plot! + return dict(gpmean=plots) + else: + raise RuntimeError('Cannot plot mean in more then 1 input dimensions') + + +def plot_density(self, plot_limits=None, fixed_inputs=None, + resolution=None, plot_raw=False, + apply_link=False, visible_dims=None, + which_data_ycols='all', + levels=35, label='gp density', + predict_kw=None, + **kwargs): + """ + Plot the confidence interval between the percentiles lower and upper. + E.g. the 95% confidence interval is $2.5, 97.5$. + Note: Only implemented for one dimension! + + 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. + + + + :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 array-like visible_dims: which columns of the input X (!) to plot (array-like or list of ints) + :param array-like which_data_ycols: which columns of y 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 dict predict_kw: the keyword arguments for the prediction. If you want to plot a specific kernel give dict(kern=) in here + """ + canvas, kwargs = pl().new_canvas(**kwargs) + X = get_x_y_var(self)[0] + helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) + helper_prediction = helper_predict_with_model(self, helper_data[2], plot_raw, + apply_link, np.linspace(2.5, 97.5, levels*2), + get_which_data_ycols(self, which_data_ycols), + predict_kw) + plots = _plot_density(self, canvas, helper_data, helper_prediction, label, **kwargs) + return pl().add_to_canvas(canvas, plots) + +def _plot_density(self, canvas, helper_data, helper_prediction, label, **kwargs): + _, free_dims, Xgrid, _, _, _, _, _ = helper_data + mu, percs, _ = helper_prediction + + update_not_existing_kwargs(kwargs, pl().defaults.density) # @UndefinedVariable + + if len(free_dims)<=1: + if len(free_dims)==1: + # 1D plotting: + fills = [] + for d in range(mu.shape[1]): + fills.append(pl().fill_gradient(canvas, Xgrid[:, free_dims[0]], [p[:,d] for p in percs], label=label, **kwargs)) + return dict(gpdensity=fills) + else: + pass # Nothing to plot! + else: + raise RuntimeError('Can only plot density in one input dimension') + +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=) 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. + """ + canvas, _ = pl().new_canvas(projection=projection, **kwargs) + X = get_x_y_var(self)[0] + helper_data = helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution) + 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 plot_data: + plots.update(_plot_data(self, canvas, which_data_rows, which_data_ycols, visible_dims, projection, "Data")) + plots.update(_plot_data_error(self, canvas, which_data_rows, which_data_ycols, visible_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")) + if hasattr(self, 'Z') and plot_inducing: + plots.update(_plot_inducing(self, canvas, visible_dims, projection, 'Inducing')) + return pl().add_to_canvas(canvas, plots, legend=legend) + + +def plot_f(self, plot_limits=None, fixed_inputs=None, + resolution=None, + apply_link=False, + which_data_ycols='all', which_data_rows='all', + visible_dims=None, + levels=20, samples=0, lower=2.5, upper=97.5, + plot_density=False, + plot_data=True, plot_inducing=True, + projection='2d', legend=True, + predict_kw=None, + **kwargs): + """ + Convinience function for plotting the fit of a GP. + This is the same as plot, except it plots the latent function fit of the GP! + + If you want fine graned control use the specific plotting functions supplied in the model. + + 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. + + + :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 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: an array specifying the input dimensions to plot (maximum two) + :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 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=) in here + :param dict error_kwargs: kwargs for the error plot for the plotting library you are using + :param kwargs plot_kwargs: kwargs for the data plot for the plotting library you are using + """ + plot(self, plot_limits, fixed_inputs, resolution, True, + apply_link, which_data_ycols, which_data_rows, + visible_dims, levels, samples, 0, + lower, upper, plot_data, plot_inducing, + plot_density, predict_kw, projection, legend) + + + +def _plot(self, canvas, plots, helper_data, helper_prediction, levels, plot_inducing=True, plot_density=False, projection='2d'): + plots.update(_plot_mean(self, canvas, helper_data, helper_prediction, levels, projection, 'Mean')) + + try: + if projection=='2d': + if not plot_density: + plots.update(_plot_confidence(self, canvas, helper_data, helper_prediction, "Confidence")) + else: + plots.update(_plot_density(self, canvas, helper_data, helper_prediction, "Density")) + except RuntimeError: + #plotting in 2d + pass + + if helper_prediction[2] is not None: + plots.update(_plot_samples(self, canvas, helper_data, helper_prediction, projection, "Samples")) + return plots \ No newline at end of file diff --git a/GPy/plotting/gpy_plot/inference_plots.py b/GPy/plotting/gpy_plot/inference_plots.py new file mode 100644 index 00000000..5fda3043 --- /dev/null +++ b/GPy/plotting/gpy_plot/inference_plots.py @@ -0,0 +1,27 @@ +# Copyright (c) 2012, GPy authors (see AUTHORS.txt). +# Licensed under the BSD 3-clause license (see LICENSE.txt) + +#import numpy as np +#import Tango +#from base_plots import gpplot, x_frame1D, x_frame2D + +from . import plotting_library as pl + +def plot_optimizer(optimizer, **kwargs): + if optimizer.trace == None: + print("No trace present so I can't plot it. Please check that the optimizer actually supplies a trace.") + else: + canvas, kwargs = pl().new_canvas(**kwargs) + plots = dict(trace=pl().plot(range(len(optimizer.trace)), optimizer.trace)) + return pl().add_to_canvas(canvas, plots, xlabel='Iteration', ylabel='f(x)') + +def plot_sgd_traces(optimizer): + figure = pl().figure(2,1) + canvas, _ = pl().new_canvas(figure, 1, 1, title="Parameters") + plots = dict(lines=[]) + for k in optimizer.param_traces.keys(): + plots['lines'].append(pl().plot(canvas, range(len(optimizer.param_traces[k])), optimizer.param_traces[k], label=k)) + pl().add_to_canvas(canvas, legend=True) + canvas, _ = pl().new_canvas(figure, 1, 2, title="Objective function") + pl().plot(canvas, range(len(optimizer.fopt_trace)), optimizer.fopt_trace) + return pl().add_to_canvas(canvas, plots, legend=True) diff --git a/GPy/plotting/gpy_plot/kernel_plots.py b/GPy/plotting/gpy_plot/kernel_plots.py new file mode 100644 index 00000000..01796d84 --- /dev/null +++ b/GPy/plotting/gpy_plot/kernel_plots.py @@ -0,0 +1,139 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy.plotting.gpy_plot.kernel_plots nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== +import numpy as np +from . import plotting_library as pl +from .. import Tango +from .plot_util import update_not_existing_kwargs, helper_for_plot_data +from ...kern.src.kern import Kern, CombinationKernel + +def plot_ARD(kernel, filtering=None, legend=False, **kwargs): + """ + If an ARD kernel is present, plot a bar representation using matplotlib + + :param fignum: figure number of the plot + :param filtering: list of names, which to use for plotting ARD parameters. + Only kernels which match names in the list of names in filtering + will be used for plotting. + :type filtering: list of names to use for ARD plot + """ + Tango.reset() + + ard_params = np.atleast_2d(kernel.input_sensitivity(summarize=False)) + bottom = 0 + last_bottom = bottom + + x = np.arange(kernel.input_dim) + + parts = [] + def visit(x): + if (not isinstance(x, CombinationKernel)) and isinstance(x, Kern): + parts.append(x) + kernel.traverse(visit) + + if filtering is None: + filtering = [k.name for k in parts] + + bars = [] + kwargs = update_not_existing_kwargs(kwargs, pl().defaults.ard) + canvas, kwargs = pl().new_canvas(xlim=(-.5, kernel.input_dim-.5), xlabel='input dimension', ylabel='sensitivity', **kwargs) + for i in range(ard_params.shape[0]): + if parts[i].name in filtering: + c = Tango.nextMedium() + bars.append(pl().barplot(canvas, x, + ard_params[i,:], color=c, + label=parts[i].name, + bottom=bottom, **kwargs)) + last_bottom = ard_params[i,:] + bottom += last_bottom + else: + print("filtering out {}".format(parts[i].name)) + + #add_bar_labels(fig, ax, [bars[-1]], bottom=bottom-last_bottom) + + return pl().add_to_canvas(canvas, bars, legend=legend) + +def plot_covariance(kernel, x=None, label=None, + plot_limits=None, visible_dims=None, resolution=None, + projection='2d', levels=20, **kwargs): + """ + Plot a kernel covariance w.r.t. another x. + + :param array-like x: the value to use for the other kernel argument (kernels are a function of two variables!) + :param plot_limits: the range over which to plot the kernel + :type plot_limits: Either (xmin, xmax) for 1D or (xmin, xmax, ymin, ymax) / ((xmin, xmax), (ymin, ymax)) for 2D + :param array-like visible_dims: input dimensions (!) to use for x. Make sure to select 2 or less dimensions to plot. + :resolution: the resolution of the lines used in plotting. for 2D this defines the grid for kernel evaluation. + :param {2d|3d} projection: What projection shall we use to plot the kernel? + :param int levels: for 2D projection, how many levels for the contour plot to use? + :param kwargs: valid kwargs for your specific plotting library + """ + X = np.ones((2, kernel.input_dim)) * [[-3], [3]] + _, free_dims, Xgrid, xx, yy, _, _, resolution = helper_for_plot_data(kernel, X, plot_limits, visible_dims, None, resolution) + + from numbers import Number + if x is None: + from ...kern.src.stationary import Stationary + x = np.ones((1, kernel.input_dim)) * (not isinstance(kernel, Stationary)) + elif isinstance(x, Number): + x = np.ones((1, kernel.input_dim))*x + K = kernel.K(Xgrid, x) + + if projection == '3d': + xlabel = 'X[:,0]' + ylabel = 'X[:,1]' + zlabel = "k(X, {!s})".format(np.asanyarray(x).tolist()) + else: + xlabel = 'X' + ylabel = "k(X, {!s})".format(np.asanyarray(x).tolist()) + zlabel = None + + canvas, kwargs = pl().new_canvas(projection=projection, xlabel=xlabel, ylabel=ylabel, zlabel=zlabel, **kwargs) + + if len(free_dims)<=2: + if len(free_dims)==1: + # 1D plotting: + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_1d) # @UndefinedVariable + plots = dict(covariance=[pl().plot(canvas, Xgrid[:, free_dims], K, label=label, **kwargs)]) + else: + if projection == '2d': + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable + plots = dict(covariance=[pl().contour(canvas, xx[:, 0], yy[0, :], + K.reshape(resolution, resolution), + levels=levels, label=label, **kwargs)]) + elif projection == '3d': + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable + plots = dict(covariance=[pl().surface(canvas, xx, yy, + K.reshape(resolution, resolution), + label=label, + **kwargs)]) + return pl().add_to_canvas(canvas, plots) + + else: + raise NotImplementedError("Cannot plot a kernel with more than two input dimensions") \ No newline at end of file diff --git a/GPy/plotting/gpy_plot/latent_plots.py b/GPy/plotting/gpy_plot/latent_plots.py new file mode 100644 index 00000000..2e5c7148 --- /dev/null +++ b/GPy/plotting/gpy_plot/latent_plots.py @@ -0,0 +1,335 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy.plotting.gpy_plot.latent_plots nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== +import numpy as np +from . import plotting_library as pl +from .plot_util import get_x_y_var,\ + update_not_existing_kwargs, \ + helper_for_plot_data, scatter_label_generator, subsample_X,\ + find_best_layout_for_subplots + +def _wait_for_updates(view, updates): + if view is not None: + try: + if updates: + clear = raw_input('yes or enter to deactivate updates - otherwise still do updates - use plots[imshow].deactivate() to clear') + if clear.lower() in 'yes' or clear == '': + view.deactivate() + else: + view.deactivate() + except AttributeError: + # No updateable view: + pass + except TypeError: + # No updateable view: + pass + + +def _plot_latent_scatter(canvas, X, visible_dims, labels, marker, num_samples, projection='2d', **kwargs): + from .. import Tango + Tango.reset() + X, labels = subsample_X(X, labels, num_samples) + scatters = [] + generate_colors = 'color' not in kwargs + for x, y, z, this_label, _, m in scatter_label_generator(labels, X, visible_dims, marker): + update_not_existing_kwargs(kwargs, pl().defaults.latent_scatter) + if generate_colors: + kwargs['color'] = Tango.nextMedium() + if projection == '3d': + scatters.append(pl().scatter(canvas, x, y, Z=z, marker=m, label=this_label, **kwargs)) + else: scatters.append(pl().scatter(canvas, x, y, marker=m, label=this_label, **kwargs)) + return scatters + +def plot_latent_scatter(self, labels=None, + which_indices=None, + legend=True, + plot_limits=None, + marker='<>^vsd', + num_samples=1000, + projection='2d', + **kwargs): + """ + Plot a scatter plot of the latent space. + + :param array-like labels: a label for each data point (row) of the inputs + :param (int, int) which_indices: which input dimensions to plot against each other + :param bool legend: whether to plot the legend on the figure + :param plot_limits: the plot limits for the plot + :type plot_limits: (xmin, xmax, ymin, ymax) or ((xmin, xmax), (ymin, ymax)) + :param str marker: markers to use - cycle if more labels then markers are given + :param kwargs: the kwargs for the scatter plots + """ + input_1, input_2, input_3 = sig_dims = self.get_most_significant_input_dimensions(which_indices) + + canvas, kwargs = pl().new_canvas(projection=projection, + xlabel='latent dimension %i' % input_1, + ylabel='latent dimension %i' % input_2, + zlabel='latent dimension %i' % input_3, **kwargs) + X, _, _ = get_x_y_var(self) + if labels is None: + labels = np.ones(self.num_data) + legend = False + else: + legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] + scatters = _plot_latent_scatter(canvas, X, sig_dims, labels, marker, num_samples, projection=projection, **kwargs) + return pl().add_to_canvas(canvas, dict(scatter=scatters), legend=legend) + + + + +def plot_latent_inducing(self, + which_indices=None, + legend=False, + plot_limits=None, + marker='^', + num_samples=1000, + projection='2d', + **kwargs): + """ + Plot a scatter plot of the inducing inputs. + + :param array-like labels: a label for each data point (row) of the inputs + :param (int, int) which_indices: which input dimensions to plot against each other + :param bool legend: whether to plot the legend on the figure + :param plot_limits: the plot limits for the plot + :type plot_limits: (xmin, xmax, ymin, ymax) or ((xmin, xmax), (ymin, ymax)) + :param str marker: markers to use - cycle if more labels then markers are given + :param kwargs: the kwargs for the scatter plots + """ + input_1, input_2, input_3 = sig_dims = self.get_most_significant_input_dimensions(which_indices) + + if 'color' not in kwargs: + kwargs['color'] = 'white' + canvas, kwargs = pl().new_canvas(projection=projection, + xlabel='latent dimension %i' % input_1, + ylabel='latent dimension %i' % input_2, + zlabel='latent dimension %i' % input_3, **kwargs) + Z = self.Z.values + labels = np.array(['inducing'] * Z.shape[0]) + scatters = _plot_latent_scatter(canvas, Z, sig_dims, labels, marker, num_samples, projection=projection, **kwargs) + return pl().add_to_canvas(canvas, dict(scatter=scatters), legend=legend) + + + + + + +def _plot_magnification(self, canvas, which_indices, Xgrid, + xmin, xmax, resolution, updates, + mean=True, covariance=True, + kern=None, + **imshow_kwargs): + def plot_function(x): + Xtest_full = np.zeros((x.shape[0], Xgrid.shape[1])) + Xtest_full[:, which_indices] = x + mf = self.predict_magnification(Xtest_full, kern=kern, mean=mean, covariance=covariance) + return mf.reshape(resolution, resolution).T + imshow_kwargs = update_not_existing_kwargs(imshow_kwargs, pl().defaults.magnification) + try: + if updates: + return pl().imshow_interact(canvas, plot_function, (xmin[0], xmax[0], xmin[1], xmax[1]), resolution=resolution, **imshow_kwargs) + else: raise NotImplementedError + except NotImplementedError: + return pl().imshow(canvas, plot_function(Xgrid[:, which_indices]), (xmin[0], xmax[0], xmin[1], xmax[1]), **imshow_kwargs) + +def plot_magnification(self, labels=None, which_indices=None, + resolution=60, marker='<>^vsd', legend=True, + plot_limits=None, + updates=False, + mean=True, covariance=True, + kern=None, num_samples=1000, + scatter_kwargs=None, **imshow_kwargs): + """ + Plot the magnification factor of the GP on the inputs. This is the + density of the GP as a gray scale. + + :param array-like labels: a label for each data point (row) of the inputs + :param (int, int) which_indices: which input dimensions to plot against each other + :param int resolution: the resolution at which we predict the magnification factor + :param str marker: markers to use - cycle if more labels then markers are given + :param bool legend: whether to plot the legend on the figure + :param plot_limits: the plot limits for the plot + :type plot_limits: (xmin, xmax, ymin, ymax) or ((xmin, xmax), (ymin, ymax)) + :param bool updates: if possible, make interactive updates using the specific library you are using + :param bool mean: use the mean of the Wishart embedding for the magnification factor + :param bool covariance: use the covariance of the Wishart embedding for the magnification factor + :param :py:class:`~GPy.kern.Kern` kern: the kernel to use for prediction + :param int num_samples: the number of samples to plot maximally. We do a stratified subsample from the labels, if the number of samples (in X) is higher then num_samples. + :param imshow_kwargs: the kwargs for the imshow (magnification factor) + :param kwargs: the kwargs for the scatter plots + """ + input_1, input_2 = which_indices = self.get_most_significant_input_dimensions(which_indices)[:2] + X = get_x_y_var(self)[0] + _, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution) + canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]), + xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs) + if (labels is not None): + legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] + else: + labels = np.ones(self.num_data) + legend = False + scatters = _plot_latent_scatter(canvas, X, which_indices, labels, marker, num_samples, projection='2d', **scatter_kwargs or {}) + view = _plot_magnification(self, canvas, which_indices[:2], Xgrid, xmin, xmax, resolution, updates, mean, covariance, kern, **imshow_kwargs) + retval = pl().add_to_canvas(canvas, dict(scatter=scatters, imshow=view), + legend=legend, + ) + _wait_for_updates(view, updates) + return retval + + + + +def _plot_latent(self, canvas, which_indices, Xgrid, + xmin, xmax, resolution, updates, + kern=None, + **imshow_kwargs): + def plot_function(x): + Xtest_full = np.zeros((x.shape[0], Xgrid.shape[1])) + Xtest_full[:, which_indices] = x + mf = np.log(self.predict(Xtest_full, kern=kern)[1]) + return mf.reshape(resolution, resolution).T + + imshow_kwargs = update_not_existing_kwargs(imshow_kwargs, pl().defaults.latent) + try: + if updates: + return pl().imshow_interact(canvas, plot_function, (xmin[0], xmax[0], xmin[1], xmax[1]), resolution=resolution, **imshow_kwargs) + else: raise NotImplementedError + except NotImplementedError: + return pl().imshow(canvas, plot_function(Xgrid[:, which_indices]), (xmin[0], xmax[0], xmin[1], xmax[1]), **imshow_kwargs) + +def plot_latent(self, labels=None, which_indices=None, + resolution=60, legend=True, + plot_limits=None, + updates=False, + kern=None, marker='<>^vsd', + num_samples=1000, + scatter_kwargs=None, **imshow_kwargs): + """ + Plot the latent space of the GP on the inputs. This is the + density of the GP posterior as a grey scale and the + scatter plot of the input dimemsions selected by which_indices. + + :param array-like labels: a label for each data point (row) of the inputs + :param (int, int) which_indices: which input dimensions to plot against each other + :param int resolution: the resolution at which we predict the magnification factor + :param bool legend: whether to plot the legend on the figure + :param plot_limits: the plot limits for the plot + :type plot_limits: (xmin, xmax, ymin, ymax) or ((xmin, xmax), (ymin, ymax)) + :param bool updates: if possible, make interactive updates using the specific library you are using + :param :py:class:`~GPy.kern.Kern` kern: the kernel to use for prediction + :param str marker: markers to use - cycle if more labels then markers are given + :param int num_samples: the number of samples to plot maximally. We do a stratified subsample from the labels, if the number of samples (in X) is higher then num_samples. + :param imshow_kwargs: the kwargs for the imshow (magnification factor) + :param scatter_kwargs: the kwargs for the scatter plots + """ + input_1, input_2 = which_indices = self.get_most_significant_input_dimensions(which_indices)[:2] + X = get_x_y_var(self)[0] + _, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution) + canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]), + xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs) + if (labels is not None): + legend = find_best_layout_for_subplots(len(np.unique(labels)))[1] + else: + labels = np.ones(self.num_data) + legend = False + scatters = _plot_latent_scatter(canvas, X, which_indices, labels, marker, num_samples, projection='2d', **scatter_kwargs or {}) + view = _plot_latent(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, updates, kern, **imshow_kwargs) + retval = pl().add_to_canvas(canvas, dict(scatter=scatters, imshow=view), legend=legend) + _wait_for_updates(view, updates) + return retval + +def _plot_steepest_gradient_map(self, canvas, which_indices, Xgrid, + xmin, xmax, resolution, output_labels, updates, + kern=None, annotation_kwargs=None, + **imshow_kwargs): + if output_labels is None: + output_labels = range(self.output_dim) + def plot_function(x): + Xgrid[:, which_indices] = x + dmu_dX = np.sqrt(((self.predictive_gradients(Xgrid, kern=kern)[0])**2).sum(1)) + #dmu_dX = self.predictive_gradients(Xgrid, kern=kern)[0].sum(1) + argmax = np.argmax(dmu_dX, 1).astype(int) + return dmu_dX.max(1).reshape(resolution, resolution).T, np.array(output_labels)[argmax].reshape(resolution, resolution).T + annotation_kwargs = update_not_existing_kwargs(annotation_kwargs or {}, pl().defaults.annotation) + imshow_kwargs = update_not_existing_kwargs(imshow_kwargs or {}, pl().defaults.gradient) + try: + if updates: + return dict(annotation=pl().annotation_heatmap_interact(canvas, plot_function, (xmin[0], xmax[0], xmin[1], xmax[1]), resolution=resolution, imshow_kwargs=imshow_kwargs, **annotation_kwargs)) + else: + raise NotImplementedError + except NotImplementedError: + imshow, annotation = pl().annotation_heatmap(canvas, *plot_function(Xgrid[:, which_indices]), extent=(xmin[0], xmax[0], xmin[1], xmax[1]), imshow_kwargs=imshow_kwargs, **annotation_kwargs) + return dict(heatmap=imshow, annotation=annotation) + +def plot_steepest_gradient_map(self, output_labels=None, data_labels=None, which_indices=None, + resolution=15, legend=True, + plot_limits=None, + updates=False, + kern=None, marker='<>^vsd', + num_samples=1000, + annotation_kwargs=None, scatter_kwargs=None, **imshow_kwargs): + + """ + Plot the latent space of the GP on the inputs. This is the + density of the GP posterior as a grey scale and the + scatter plot of the input dimemsions selected by which_indices. + + :param array-like labels: a label for each data point (row) of the inputs + :param (int, int) which_indices: which input dimensions to plot against each other + :param int resolution: the resolution at which we predict the magnification factor + :param bool legend: whether to plot the legend on the figure, if int plot legend columns on legend + :param plot_limits: the plot limits for the plot + :type plot_limits: (xmin, xmax, ymin, ymax) or ((xmin, xmax), (ymin, ymax)) + :param bool updates: if possible, make interactive updates using the specific library you are using + :param :py:class:`~GPy.kern.Kern` kern: the kernel to use for prediction + :param str marker: markers to use - cycle if more labels then markers are given + :param int num_samples: the number of samples to plot maximally. We do a stratified subsample from the labels, if the number of samples (in X) is higher then num_samples. + :param imshow_kwargs: the kwargs for the imshow (magnification factor) + :param annotation_kwargs: the kwargs for the annotation plot + :param scatter_kwargs: the kwargs for the scatter plots + """ + input_1, input_2 = which_indices = self.get_most_significant_input_dimensions(which_indices)[:2] + X = get_x_y_var(self)[0] + _, _, Xgrid, _, _, xmin, xmax, resolution = helper_for_plot_data(self, X, plot_limits, which_indices, None, resolution) + canvas, imshow_kwargs = pl().new_canvas(xlim=(xmin[0], xmax[0]), ylim=(xmin[1], xmax[1]), + xlabel='latent dimension %i' % input_1, ylabel='latent dimension %i' % input_2, **imshow_kwargs) + if (data_labels is not None): + legend = find_best_layout_for_subplots(len(np.unique(data_labels)))[1] + else: + data_labels = np.ones(self.num_data) + legend = False + plots = dict(scatter=_plot_latent_scatter(canvas, X, which_indices, data_labels, marker, num_samples, **scatter_kwargs or {})) + plots.update(_plot_steepest_gradient_map(self, canvas, which_indices, Xgrid, xmin, xmax, resolution, output_labels, updates, kern, annotation_kwargs=annotation_kwargs, **imshow_kwargs)) + retval = pl().add_to_canvas(canvas, plots, legend=legend) + _wait_for_updates(plots['annotation'], updates) + return retval + + + + diff --git a/GPy/plotting/gpy_plot/plot_util.py b/GPy/plotting/gpy_plot/plot_util.py new file mode 100644 index 00000000..22d6627c --- /dev/null +++ b/GPy/plotting/gpy_plot/plot_util.py @@ -0,0 +1,375 @@ +#=============================================================================== +# Copyright (c) 2012-2015, GPy authors (see AUTHORS.txt). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== + +import numpy as np +from scipy import sparse +import itertools + +def in_ipynb(): + try: + cfg = get_ipython().config + return 'IPKernelApp' in cfg + except NameError: + return False + +def find_best_layout_for_subplots(num_subplots): + r, c = 1, 1 + while (r*c) < num_subplots: + if (c==(r+1)) or (r==c): + c += 1 + elif c==(r+2): + r += 1 + c -= 1 + return r, c + +def helper_predict_with_model(self, Xgrid, plot_raw, apply_link, percentiles, which_data_ycols, predict_kw, samples=0): + """ + Make the right decisions for prediction with a model + based on the standard arguments of plotting. + + This is quite complex and will take a while to understand, + so do not change anything in here lightly!!! + """ + # Put some standards into the predict_kw so that prediction is done automatically: + if predict_kw is None: + predict_kw = {} + if 'likelihood' not in predict_kw: + if plot_raw: + from ...likelihoods import Gaussian + from ...likelihoods.link_functions import Identity + lik = Gaussian(Identity(), 1e-9) # Make the likelihood not add any noise + else: + lik = None + predict_kw['likelihood'] = lik + if 'Y_metadata' not in predict_kw: + predict_kw['Y_metadata'] = {} + if 'output_index' not in predict_kw['Y_metadata']: + predict_kw['Y_metadata']['output_index'] = Xgrid[:,-1:].astype(np.int) + + mu, _ = self.predict(Xgrid, **predict_kw) + + if percentiles is not None: + percentiles = self.predict_quantiles(Xgrid, quantiles=percentiles, **predict_kw) + else: percentiles = [] + + if samples > 0: + fsamples = self.posterior_samples(Xgrid, full_cov=True, size=samples, **predict_kw) + fsamples = fsamples[which_data_ycols] if fsamples.ndim == 3 else fsamples + else: + fsamples = None + + # Filter out the ycolums which we want to plot: + retmu = mu[:, which_data_ycols] + percs = [p[:, which_data_ycols] for p in percentiles] + + if plot_raw and apply_link: + for i in range(len(which_data_ycols)): + retmu[:, [i]] = self.likelihood.gp_link.transf(mu[:, [i]]) + for perc in percs: + perc[:, [i]] = self.likelihood.gp_link.transf(perc[:, [i]]) + if fsamples is not None and fsamples.ndim == 3: + for s in range(fsamples.shape[-1]): + fsamples[i, :, s] = self.likelihood.gp_link.transf(fsamples[i, :, s]) + elif fsamples is not None: + for s in range(fsamples.shape[-1]): + fsamples[:, s] = self.likelihood.gp_link.transf(fsamples[:, s]) + return retmu, percs, fsamples + +def helper_for_plot_data(self, X, plot_limits, visible_dims, fixed_inputs, resolution): + """ + Figure out the data, free_dims and create an Xgrid for + the prediction. + + This is only implemented for two dimensions for now! + """ + #work out what the inputs are for plotting (1D or 2D) + if fixed_inputs is None: + fixed_inputs = [] + fixed_dims = get_fixed_dims(fixed_inputs) + free_dims = get_free_dims(self, visible_dims, fixed_dims) + + if len(free_dims) == 1: + #define the frame on which to plot + resolution = resolution or 200 + Xnew, xmin, xmax = x_frame1D(X[:,free_dims], plot_limits=plot_limits, resolution=resolution) + Xgrid = np.zeros((Xnew.shape[0],self.input_dim)) + Xgrid[:,free_dims] = Xnew + for i,v in fixed_inputs: + Xgrid[:,i] = v + x = Xgrid + y = None + elif len(free_dims) == 2: + #define the frame for plotting on + resolution = resolution or 35 + Xnew, x, y, xmin, xmax = x_frame2D(X[:,free_dims], plot_limits, resolution) + Xgrid = np.zeros((Xnew.shape[0], self.input_dim)) + Xgrid[:,free_dims] = Xnew + for i,v in fixed_inputs: + Xgrid[:,i] = v + else: + raise TypeError("calculated free_dims {} from visible_dims {} and fixed_dims {} is neither 1D nor 2D".format(free_dims, visible_dims, fixed_dims)) + return fixed_dims, free_dims, Xgrid, x, y, xmin, xmax, resolution + +def scatter_label_generator(labels, X, visible_dims, marker=None): + ulabels = [] + for lab in labels: + if not lab in ulabels: + ulabels.append(lab) + if marker is not None: + marker = itertools.cycle(list(marker)) + else: + m = None + + try: + input_1, input_2, input_3 = visible_dims + except: + try: + # tuple or int? + input_1, input_2 = visible_dims + input_3 = None + except: + input_1 = visible_dims + input_2 = input_3 = None + + for ul in ulabels: + from numbers import Number + if isinstance(ul, str): + try: + this_label = unicode(ul) + except NameError: + #python3 + this_label = ul + elif isinstance(ul, Number): + this_label = 'class {!s}'.format(ul) + else: + this_label = ul + + if marker is not None: + m = next(marker) + + index = np.nonzero(labels == ul)[0] + + if input_2 is None: + x = X[index, input_1] + y = np.zeros(index.size) + z = None + elif input_3 is None: + x = X[index, input_1] + y = X[index, input_2] + z = None + else: + x = X[index, input_1] + y = X[index, input_2] + z = X[index, input_3] + yield x, y, z, this_label, index, m + +def subsample_X(X, labels, num_samples=1000): + """ + Stratified subsampling if labels are given. + This means due to rounding errors you might get a little differences between the + num_samples and the returned subsampled X. + """ + if X.shape[0] > num_samples: + print("Warning: subsampling X, as it has more samples then 1000. X.shape={!s}".format(X.shape)) + if labels is not None: + subsample = [] + for _, _, _, _, index, _ in scatter_label_generator(labels, X, (0, None, None)): + subsample.append(np.random.choice(index, size=max(2, int(index.size*(float(num_samples)/X.shape[0]))), replace=False)) + subsample = np.hstack(subsample) + else: + subsample = np.random.choice(X.shape[0], size=1000, replace=False) + X = X[subsample] + labels = labels[subsample] + #======================================================================= + # <<>> + # <<>> + # plt.close('all') + # fig, ax = plt.subplots(1,1) + # from GPy.plotting.matplot_dep.dim_reduction_plots import most_significant_input_dimensions + # import matplotlib.patches as mpatches + # i1, i2 = most_significant_input_dimensions(m, None) + # xmin, xmax = 100, -100 + # ymin, ymax = 100, -100 + # legend_handles = [] + # + # X = m.X.mean[:, [i1, i2]] + # X = m.X.variance[:, [i1, i2]] + # + # xmin = X[:,0].min(); xmax = X[:,0].max() + # ymin = X[:,1].min(); ymax = X[:,1].max() + # range_ = [[xmin, xmax], [ymin, ymax]] + # ul = np.unique(labels) + # + # for i, l in enumerate(ul): + # #cdict = dict(red =[(0., colors[i][0], colors[i][0]), (1., colors[i][0], colors[i][0])], + # # green=[(0., colors[i][0], colors[i][1]), (1., colors[i][1], colors[i][1])], + # # blue =[(0., colors[i][0], colors[i][2]), (1., colors[i][2], colors[i][2])], + # # alpha=[(0., 0., .0), (.5, .5, .5), (1., .5, .5)]) + # #cmap = LinearSegmentedColormap('{}'.format(l), cdict) + # cmap = LinearSegmentedColormap.from_list('cmap_{}'.format(str(l)), [colors[i], colors[i]], 255) + # cmap._init() + # #alphas = .5*(1+scipy.special.erf(np.linspace(-2,2, cmap.N+3)))#np.log(np.linspace(np.exp(0), np.exp(1.), cmap.N+3)) + # alphas = (scipy.special.erf(np.linspace(0,2.4, cmap.N+3)))#np.log(np.linspace(np.exp(0), np.exp(1.), cmap.N+3)) + # cmap._lut[:, -1] = alphas + # print l + # x, y = X[labels==l].T + # + # heatmap, xedges, yedges = np.histogram2d(x, y, bins=300, range=range_) + # #heatmap, xedges, yedges = np.histogram2d(x, y, bins=100) + # + # im = ax.imshow(heatmap, extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]], cmap=cmap, aspect='auto', interpolation='nearest', label=str(l)) + # legend_handles.append(mpatches.Patch(color=colors[i], label=l)) + # ax.set_xlim(xmin, xmax) + # ax.set_ylim(ymin, ymax) + # plt.legend(legend_handles, [l.get_label() for l in legend_handles]) + # plt.draw() + # plt.show() + #======================================================================= + return X, labels + + +def update_not_existing_kwargs(to_update, update_from): + """ + This function updates the keyword aguments from update_from in + to_update, only if the keys are not set in to_update. + + This is used for updated kwargs from the default dicts. + """ + if to_update is None: + to_update = {} + to_update.update({k:v for k,v in update_from.items() if k not in to_update}) + return to_update + +def get_x_y_var(model): + """ + Either the the data from a model as + X the inputs, + X_variance the variance of the inputs ([default: None]) + and Y the outputs + + If (X, X_variance, Y) is given, this just returns. + + :returns: (X, X_variance, Y) + """ + # model given + if hasattr(model, 'has_uncertain_inputs') and model.has_uncertain_inputs(): + X = model.X.mean.values + X_variance = model.X.variance.values + else: + X = model.X.values + X_variance = None + Y = model.Y.values + if sparse.issparse(Y): Y = Y.todense().view(np.ndarray) + return X, X_variance, Y + +def get_free_dims(model, visible_dims, fixed_dims): + """ + work out what the inputs are for plotting (1D or 2D) + + The visible dimensions are the dimensions, which are visible. + the fixed_dims are the fixed dimensions for this. + + The free_dims are then the visible dims without the fixed dims. + """ + if visible_dims is None: + visible_dims = np.arange(model.input_dim) + dims = np.asanyarray(visible_dims) + if fixed_dims is not None: + dims = np.setdiff1d(dims, fixed_dims) + return np.asanyarray([dim for dim in dims if dim is not None]) + + +def get_fixed_dims(fixed_inputs): + """ + Work out the fixed dimensions from the fixed_inputs list of tuples. + """ + return np.array([i for i,_ in fixed_inputs]) + +def get_which_data_ycols(model, which_data_ycols): + """ + Helper to get the data columns to plot. + """ + if which_data_ycols == 'all' or which_data_ycols is None: + return np.arange(model.output_dim) + return which_data_ycols + +def get_which_data_rows(model, which_data_rows): + """ + Helper to get the data rows to plot. + """ + if which_data_rows == 'all' or which_data_rows is None: + return slice(None) + return which_data_rows + +def x_frame1D(X,plot_limits=None,resolution=None): + """ + Internal helper function for making plots, returns a set of input values to plot as well as lower and upper limits + """ + assert X.shape[1] ==1, "x_frame1D is defined for one-dimensional inputs" + if plot_limits is None: + from ...core.parameterization.variational import VariationalPosterior + if isinstance(X, VariationalPosterior): + xmin,xmax = X.mean.min(0),X.mean.max(0) + else: + xmin,xmax = X.min(0),X.max(0) + xmin, xmax = xmin-0.25*(xmax-xmin), xmax+0.25*(xmax-xmin) + elif len(plot_limits) == 2: + xmin, xmax = plot_limits + else: + raise ValueError("Bad limits for plotting") + + Xnew = np.linspace(xmin,xmax,resolution or 200)[:,None] + return Xnew, xmin, xmax + +def x_frame2D(X,plot_limits=None,resolution=None): + """ + Internal helper function for making plots, returns a set of input values to plot as well as lower and upper limits + """ + assert X.shape[1]==2, "x_frame2D is defined for two-dimensional inputs" + if plot_limits is None: + xmin, xmax = X.min(0),X.max(0) + xmin, xmax = xmin-0.075*(xmax-xmin), xmax+0.075*(xmax-xmin) + elif len(plot_limits) == 2: + xmin, xmax = plot_limits + try: + xmin = xmin[0], xmin[1] + except: + # only one limit given, copy over to other lim + xmin = [plot_limits[0], plot_limits[0]] + xmax = [plot_limits[1], plot_limits[1]] + elif len(plot_limits) == 4: + xmin, xmax = (plot_limits[0], plot_limits[2]), (plot_limits[1], plot_limits[3]) + else: + raise ValueError("Bad limits for plotting") + + resolution = resolution or 50 + xx, yy = np.mgrid[xmin[0]:xmax[0]:1j*resolution,xmin[1]:xmax[1]:1j*resolution] + Xnew = np.vstack((xx.flatten(),yy.flatten())).T + return Xnew, xx, yy, xmin, xmax \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/__init__.py b/GPy/plotting/matplot_dep/__init__.py index a72e448f..e9d2395d 100644 --- a/GPy/plotting/matplot_dep/__init__.py +++ b/GPy/plotting/matplot_dep/__init__.py @@ -1,18 +1,21 @@ # Copyright (c) 2014, GPy authors (see AUTHORS.txt). # Licensed under the BSD 3-clause license (see LICENSE.txt) -from . import base_plots -from . import models_plots -from . import priors_plots -from . import variational_plots -from . import kernel_plots -from . import dim_reduction_plots -from . import mapping_plots -from . import Tango -from . import visualize -from . import latent_space_visualizations -from . import netpbmfile -from . import inference_plots -from . import maps -from . import img_plots -from .ssgplvm import SSGPLVM_plot +# from . import base_plots +# from . import models_plots +# from . import priors_plots +# from . import variational_plots +# from . import kernel_plots +# from . import dim_reduction_plots +# from . import mapping_plots +# from GPy.plotting.gpy_plot import Tango +# from . import visualize +# from . import latent_space_visualizations +# from . import inference_plots +# from . import maps +# from . import img_plots +# from .ssgplvm import SSGPLVM_plot + + +from .util import align_subplot_array, align_subplots, fewerXticks, removeRightTicks, removeUpperTicks +from . import controllers \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/base_plots.py b/GPy/plotting/matplot_dep/base_plots.py deleted file mode 100644 index 5e513ec2..00000000 --- a/GPy/plotting/matplot_dep/base_plots.py +++ /dev/null @@ -1,181 +0,0 @@ -# #Copyright (c) 2012, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) -from matplotlib import pyplot as pb -import numpy as np - -def ax_default(fignum, ax): - if ax is None: - fig = pb.figure(fignum) - ax = fig.add_subplot(111) - else: - fig = ax.figure - return fig, ax - -def meanplot(x, mu, color='#3300FF', ax=None, fignum=None, linewidth=2,**kw): - _, axes = ax_default(fignum, ax) - return axes.plot(x,mu,color=color,linewidth=linewidth,**kw) - -def gpplot(x, mu, lower, upper, edgecol='#3300FF', fillcol='#33CCFF', ax=None, fignum=None, **kwargs): - _, axes = ax_default(fignum, ax) - - mu = mu.flatten() - x = x.flatten() - lower = lower.flatten() - upper = upper.flatten() - - plots = [] - - #here's the mean - plots.append(meanplot(x, mu, edgecol, axes)) - - #here's the box - kwargs['linewidth']=0.5 - if not 'alpha' in kwargs.keys(): - kwargs['alpha'] = 0.3 - plots.append(axes.fill(np.hstack((x,x[::-1])),np.hstack((upper,lower[::-1])),color=fillcol,**kwargs)) - - #this is the edge: - plots.append(meanplot(x, upper,color=edgecol,linewidth=0.2,ax=axes)) - plots.append(meanplot(x, lower,color=edgecol,linewidth=0.2,ax=axes)) - - return plots - - -def gperrors(x, mu, lower, upper, edgecol=None, ax=None, fignum=None, **kwargs): - _, axes = ax_default(fignum, ax) - - mu = mu.flatten() - x = x.flatten() - lower = lower.flatten() - upper = upper.flatten() - - plots = [] - - if edgecol is None: - edgecol='#3300FF' - - if not 'alpha' in kwargs.keys(): - kwargs['alpha'] = 1. - - - if not 'lw' in kwargs.keys(): - kwargs['lw'] = 1. - - - plots.append(axes.errorbar(x,mu,yerr=np.vstack([mu-lower,upper-mu]),color=edgecol,**kwargs)) - plots[-1][0].remove() - return plots - - -def removeRightTicks(ax=None): - ax = ax or pb.gca() - for i, line in enumerate(ax.get_yticklines()): - if i%2 == 1: # odd indices - line.set_visible(False) - -def removeUpperTicks(ax=None): - ax = ax or pb.gca() - for i, line in enumerate(ax.get_xticklines()): - if i%2 == 1: # odd indices - line.set_visible(False) - -def fewerXticks(ax=None,divideby=2): - ax = ax or pb.gca() - ax.set_xticks(ax.get_xticks()[::divideby]) - -def align_subplots(N,M,xlim=None, ylim=None): - """make all of the subplots have the same limits, turn off unnecessary ticks""" - #find sensible xlim,ylim - if xlim is None: - xlim = [np.inf,-np.inf] - for i in range(N*M): - pb.subplot(N,M,i+1) - xlim[0] = min(xlim[0],pb.xlim()[0]) - xlim[1] = max(xlim[1],pb.xlim()[1]) - if ylim is None: - ylim = [np.inf,-np.inf] - for i in range(N*M): - pb.subplot(N,M,i+1) - ylim[0] = min(ylim[0],pb.ylim()[0]) - ylim[1] = max(ylim[1],pb.ylim()[1]) - - for i in range(N*M): - pb.subplot(N,M,i+1) - pb.xlim(xlim) - pb.ylim(ylim) - if (i)%M: - pb.yticks([]) - else: - removeRightTicks() - if i<(M*(N-1)): - pb.xticks([]) - else: - removeUpperTicks() - -def align_subplot_array(axes,xlim=None, ylim=None): - """ - Make all of the axes in the array hae the same limits, turn off unnecessary ticks - use pb.subplots() to get an array of axes - """ - #find sensible xlim,ylim - if xlim is None: - xlim = [np.inf,-np.inf] - for ax in axes.flatten(): - xlim[0] = min(xlim[0],ax.get_xlim()[0]) - xlim[1] = max(xlim[1],ax.get_xlim()[1]) - if ylim is None: - ylim = [np.inf,-np.inf] - for ax in axes.flatten(): - ylim[0] = min(ylim[0],ax.get_ylim()[0]) - ylim[1] = max(ylim[1],ax.get_ylim()[1]) - - N,M = axes.shape - for i,ax in enumerate(axes.flatten()): - ax.set_xlim(xlim) - ax.set_ylim(ylim) - if (i)%M: - ax.set_yticks([]) - else: - removeRightTicks(ax) - if i<(M*(N-1)): - ax.set_xticks([]) - else: - removeUpperTicks(ax) - -def x_frame1D(X,plot_limits=None,resolution=None): - """ - Internal helper function for making plots, returns a set of input values to plot as well as lower and upper limits - """ - assert X.shape[1] ==1, "x_frame1D is defined for one-dimensional inputs" - if plot_limits is None: - from ...core.parameterization.variational import VariationalPosterior - if isinstance(X, VariationalPosterior): - xmin,xmax = X.mean.min(0),X.mean.max(0) - else: - xmin,xmax = X.min(0),X.max(0) - xmin, xmax = xmin-0.2*(xmax-xmin), xmax+0.2*(xmax-xmin) - elif len(plot_limits)==2: - xmin, xmax = plot_limits - else: - raise ValueError("Bad limits for plotting") - - Xnew = np.linspace(xmin,xmax,resolution or 200)[:,None] - return Xnew, xmin, xmax - -def x_frame2D(X,plot_limits=None,resolution=None): - """ - Internal helper function for making plots, returns a set of input values to plot as well as lower and upper limits - """ - assert X.shape[1] ==2, "x_frame2D is defined for two-dimensional inputs" - if plot_limits is None: - xmin,xmax = X.min(0),X.max(0) - xmin, xmax = xmin-0.2*(xmax-xmin), xmax+0.2*(xmax-xmin) - elif len(plot_limits)==2: - xmin, xmax = plot_limits - else: - raise ValueError("Bad limits for plotting") - - resolution = resolution or 50 - xx,yy = np.mgrid[xmin[0]:xmax[0]:1j*resolution,xmin[1]:xmax[1]:1j*resolution] - Xnew = np.vstack((xx.flatten(),yy.flatten())).T - return Xnew, xx, yy, xmin, xmax diff --git a/GPy/plotting/matplot_dep/controllers/__init__.py b/GPy/plotting/matplot_dep/controllers/__init__.py new file mode 100644 index 00000000..61cfb73b --- /dev/null +++ b/GPy/plotting/matplot_dep/controllers/__init__.py @@ -0,0 +1 @@ +from .imshow_controller import ImshowController, ImAnnotateController \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/axis_event_controller.py b/GPy/plotting/matplot_dep/controllers/axis_event_controller.py similarity index 87% rename from GPy/plotting/matplot_dep/latent_space_visualizations/controllers/axis_event_controller.py rename to GPy/plotting/matplot_dep/controllers/axis_event_controller.py index 15fcd098..0e721d8d 100644 --- a/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/axis_event_controller.py +++ b/GPy/plotting/matplot_dep/controllers/axis_event_controller.py @@ -14,7 +14,7 @@ class AxisEventController(object): return self def deactivate(self): for cb_class in self.ax.callbacks.callbacks.values(): - for cb_num in cb_class.keys(): + for cb_num in dict(cb_class).keys(): self.ax.callbacks.disconnect(cb_num) def activate(self): self.ax.callbacks.connect('xlim_changed', self.xlim_changed) @@ -97,22 +97,19 @@ class BufferedAxisChangedController(AxisChangedController): :param kwargs: additional kwargs are for pyplot.imshow(**kwargs) """ super(BufferedAxisChangedController, self).__init__(ax, update_lim=update_lim) + self.resolution = resolution self.plot_function = plot_function - xmin, ymin, xmax, ymax = plot_limits#self._x_lim # self._compute_buffered(*self._x_lim) + xmin, xmax, ymin, ymax = plot_limits#self._x_lim # self._compute_buffered(*self._x_lim) # imshow acts on the limits of the plot, this is why we need to override the limits here, to make sure the right plot limits are used: self._x_lim = xmin, xmax self._y_lim = ymin, ymax - self.resolution = resolution - self._not_init = False self.view = self._init_view(self.ax, self.recompute_X(buffered=False), xmin, xmax, ymin, ymax, **kwargs) - self._not_init = True def update(self, ax): super(BufferedAxisChangedController, self).update(ax) - if self._not_init: - xmin, xmax = self._compute_buffered(*self._x_lim) - ymin, ymax = self._compute_buffered(*self._y_lim) - self.update_view(self.view, self.recompute_X(), xmin, xmax, ymin, ymax) + xmin, xmax = self._compute_buffered(*self._x_lim) + ymin, ymax = self._compute_buffered(*self._y_lim) + self.update_view(self.view, self.recompute_X(), xmin, xmax, ymin, ymax) def _init_view(self, ax, X, xmin, xmax, ymin, ymax): raise NotImplementedError('return view for this controller') @@ -129,13 +126,7 @@ class BufferedAxisChangedController(AxisChangedController): return numpy.hstack((x.flatten()[:, None], y.flatten()[:, None])) def recompute_X(self, buffered=True): - X = self.plot_function(self.get_grid(buffered)) - if isinstance(X, (tuple, list)): - for x in X: - x.shape = [self.resolution, self.resolution] - x[:, :] = x.T[::-1, :] - return X - return X.reshape(self.resolution, self.resolution).T[::-1, :] + return self.plot_function(self.get_grid(buffered)) def _compute_buffered(self, mi, ma): buffersize = self._buffersize() diff --git a/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/imshow_controller.py b/GPy/plotting/matplot_dep/controllers/imshow_controller.py similarity index 68% rename from GPy/plotting/matplot_dep/latent_space_visualizations/controllers/imshow_controller.py rename to GPy/plotting/matplot_dep/controllers/imshow_controller.py index 66c9a018..d67c9b4b 100644 --- a/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/imshow_controller.py +++ b/GPy/plotting/matplot_dep/controllers/imshow_controller.py @@ -9,7 +9,7 @@ import numpy class ImshowController(BufferedAxisChangedController): - def __init__(self, ax, plot_function, plot_limits, resolution=50, update_lim=.8, **kwargs): + def __init__(self, ax, plot_function, plot_limits, resolution=50, update_lim=.9, **kwargs): """ :param plot_function: function to use for creating image for plotting (return ndarray-like) @@ -22,19 +22,25 @@ class ImshowController(BufferedAxisChangedController): """ super(ImshowController, self).__init__(ax, plot_function, plot_limits, resolution, update_lim, **kwargs) - def _init_view(self, ax, X, xmin, xmax, ymin, ymax, **kwargs): - return ax.imshow(X, extent=(xmin, xmax, - ymin, ymax), - vmin=X.min(), - vmax=X.max(), - **kwargs) + def _init_view(self, canvas, X, xmin, xmax, ymin, ymax, vmin=None, vmax=None, **kwargs): + #xoffset, yoffset = 0, 0#self._offsets(xmin, xmax, ymin, ymax) + return canvas.imshow(X, extent=(xmin, xmax, + ymin, ymax), + vmin=vmin, vmax=vmax, + **kwargs) def update_view(self, view, X, xmin, xmax, ymin, ymax): view.set_data(X) - view.set_extent((xmin, xmax, ymin, ymax)) + xoffset, yoffset = 0, 0#self._offsets(xmin, xmax, ymin, ymax) + view.set_extent((xmin-xoffset, xmax+xoffset, + ymin-yoffset, ymax+yoffset)) + + def _offsets(self, xmin, xmax, ymin, ymax): + return float(xmax - xmin) / (2 * self.resolution), float(ymax - ymin) / (2 * self.resolution) + class ImAnnotateController(ImshowController): - def __init__(self, ax, plot_function, plot_limits, resolution=20, update_lim=.99, **kwargs): + def __init__(self, ax, plot_function, plot_limits, resolution=20, update_lim=.99, imshow_kwargs=None, **kwargs): """ :param plot_function: function to use for creating image for plotting (return ndarray-like) @@ -45,15 +51,16 @@ class ImAnnotateController(ImshowController): :param text_props: kwargs for pyplot.text(**text_props) :param kwargs: additional kwargs are for pyplot.imshow(**kwargs) """ + self.imshow_kwargs = imshow_kwargs or {} super(ImAnnotateController, self).__init__(ax, plot_function, plot_limits, resolution, update_lim, **kwargs) - def _init_view(self, ax, X, xmin, xmax, ymin, ymax, text_props={}, **kwargs): - view = [super(ImAnnotateController, self)._init_view(ax, X[0], xmin, xmax, ymin, ymax, **kwargs)] + def _init_view(self, ax, X, xmin, xmax, ymin, ymax, **kwargs): + view = [super(ImAnnotateController, self)._init_view(ax, X[0], xmin, xmax, ymin, ymax, **self.imshow_kwargs)] xoffset, yoffset = self._offsets(xmin, xmax, ymin, ymax) xlin = numpy.linspace(xmin, xmax, self.resolution, endpoint=False) ylin = numpy.linspace(ymin, ymax, self.resolution, endpoint=False) - for [i, x], [j, y] in itertools.product(enumerate(xlin), enumerate(ylin[::-1])): - view.append(ax.text(x + xoffset, y + yoffset, "{}".format(X[1][j, i]), ha='center', va='center', **text_props)) + for [i, x], [j, y] in itertools.product(enumerate(xlin), enumerate(ylin)): + view.append(ax.text(x+xoffset, y+yoffset, "{}".format(X[1][j, i]), ha='center', va='center', **kwargs)) return view def update_view(self, view, X, xmin, xmax, ymin, ymax): @@ -61,11 +68,8 @@ class ImAnnotateController(ImshowController): xoffset, yoffset = self._offsets(xmin, xmax, ymin, ymax) xlin = numpy.linspace(xmin, xmax, self.resolution, endpoint=False) ylin = numpy.linspace(ymin, ymax, self.resolution, endpoint=False) - for [[i, x], [j, y]], text in itertools.izip(itertools.product(enumerate(xlin), enumerate(ylin[::-1])), view[1:]): - text.set_x(x + xoffset) - text.set_y(y + yoffset) + for [[i, x], [j, y]], text in zip(itertools.product(enumerate(xlin), enumerate(ylin)), view[1:]): + text.set_x(x+xoffset) + text.set_y(y+yoffset) text.set_text("{}".format(X[1][j, i])) - return view - - def _offsets(self, xmin, xmax, ymin, ymax): - return (xmax - xmin) / (2 * self.resolution), (ymax - ymin) / (2 * self.resolution) + return view \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/defaults.py b/GPy/plotting/matplot_dep/defaults.py new file mode 100644 index 00000000..eab98298 --- /dev/null +++ b/GPy/plotting/matplot_dep/defaults.py @@ -0,0 +1,75 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== + +from matplotlib import cm +from .. import Tango + +''' +This file is for defaults for the gpy plot, specific to the plotting library. + +Create a kwargs dictionary with the right name for the plotting function +you are implementing. If you do not provide defaults, the default behaviour of +the plotting library will be used. + +In the code, always ise plotting.gpy_plots.defaults to get the defaults, as +it gives back an empty default, when defaults are not defined. +''' + +# Data plots: +data_1d = dict(lw=1.5, marker='x', edgecolor='k') +data_2d = dict(s=35, edgecolors='none', linewidth=0., cmap=cm.get_cmap('hot'), alpha=.5) +inducing_1d = dict(lw=0, s=500, facecolors=Tango.colorsHex['darkRed']) +inducing_2d = dict(s=14, edgecolors='k', linewidth=.4, facecolors='white', alpha=.5, marker='^') +inducing_3d = dict(lw=.3, s=500, facecolors='white', edgecolors='k') +xerrorbar = dict(color='k', fmt='none', elinewidth=.5, alpha=.5) +yerrorbar = dict(color=Tango.colorsHex['darkRed'], fmt='none', elinewidth=.5, alpha=.5) + +# GP plots: +meanplot_1d = dict(color=Tango.colorsHex['mediumBlue'], linewidth=2) +meanplot_2d = dict(cmap='hot', linewidth=.5) +meanplot_3d = dict(linewidth=0, antialiased=True, cstride=1, rstride=1, cmap='hot', alpha=.3) +samples_1d = dict(color=Tango.colorsHex['mediumBlue'], linewidth=.3) +samples_3d = dict(cmap='hot', alpha=.1, antialiased=True, cstride=1, rstride=1, linewidth=0) +confidence_interval = dict(edgecolor=Tango.colorsHex['darkBlue'], linewidth=.5, color=Tango.colorsHex['lightBlue'],alpha=.2) +density = dict(alpha=.5, color=Tango.colorsHex['lightBlue']) + +# GPLVM plots: +data_y_1d = dict(linewidth=0, cmap='RdBu', s=40) +data_y_1d_plot = dict(color='k', linewidth=1.5) + +# Kernel plots: +ard = dict(edgecolor='k', linewidth=1.2) + +# Input plots: +latent = dict(aspect='auto', cmap='Greys', interpolation='bicubic') +gradient = dict(aspect='auto', cmap='RdBu', interpolation='nearest', alpha=.7) +magnification = dict(aspect='auto', cmap='Greys', interpolation='bicubic') +latent_scatter = dict(s=40, linewidth=.2, edgecolor='k', alpha=.9) +annotation = dict(fontdict=dict(family='sans-serif', weight='light', fontsize=9), zorder=.3, alpha=.7) \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/dim_reduction_plots.py b/GPy/plotting/matplot_dep/dim_reduction_plots.py deleted file mode 100644 index 40da7cfd..00000000 --- a/GPy/plotting/matplot_dep/dim_reduction_plots.py +++ /dev/null @@ -1,423 +0,0 @@ -# Copyright (c) 2012, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - -import numpy as np -from .latent_space_visualizations.controllers.imshow_controller import ImshowController,ImAnnotateController -from ...core.parameterization.variational import VariationalPosterior -from .base_plots import x_frame2D -import itertools -try: - from . import Tango - from matplotlib.cm import get_cmap - from matplotlib import pyplot as pb - from matplotlib import cm -except: - pass - -def most_significant_input_dimensions(model, which_indices): - """ - Determine which dimensions should be plotted - """ - if which_indices is None: - if model.input_dim == 1: - input_1 = 0 - input_2 = None - if model.input_dim == 2: - input_1, input_2 = 0, 1 - else: - try: - input_1, input_2 = np.argsort(model.input_sensitivity())[::-1][:2] - except: - raise ValueError("cannot automatically determine which dimensions to plot, please pass 'which_indices'") - else: - input_1, input_2 = which_indices - return input_1, input_2 - -def plot_latent(model, labels=None, which_indices=None, - resolution=50, ax=None, marker='o', s=40, - fignum=None, plot_inducing=False, legend=True, - plot_limits=None, - aspect='auto', updates=False, predict_kwargs={}, imshow_kwargs={}): - """ - :param labels: a np.array of size model.num_data containing labels for the points (can be number, strings, etc) - :param resolution: the resolution of the grid on which to evaluate the predictive variance - """ - if ax is None: - fig = pb.figure(num=fignum) - ax = fig.add_subplot(111) - else: - fig = ax.figure - Tango.reset() - - if labels is None: - labels = np.ones(model.num_data) - - input_1, input_2 = most_significant_input_dimensions(model, which_indices) - - #fethch the data points X that we'd like to plot - X = model.X - if isinstance(X, VariationalPosterior): - X = X.mean - else: - X = X - - - if X.shape[0] > 1000: - print("Warning: subsampling X, as it has more samples then 1000. X.shape={!s}".format(X.shape)) - subsample = np.random.choice(X.shape[0], size=1000, replace=False) - X = X[subsample] - labels = labels[subsample] - #======================================================================= - # <<>> - # <<>> - # plt.close('all') - # fig, ax = plt.subplots(1,1) - # from GPy.plotting.matplot_dep.dim_reduction_plots import most_significant_input_dimensions - # import matplotlib.patches as mpatches - # i1, i2 = most_significant_input_dimensions(m, None) - # xmin, xmax = 100, -100 - # ymin, ymax = 100, -100 - # legend_handles = [] - # - # X = m.X.mean[:, [i1, i2]] - # X = m.X.variance[:, [i1, i2]] - # - # xmin = X[:,0].min(); xmax = X[:,0].max() - # ymin = X[:,1].min(); ymax = X[:,1].max() - # range_ = [[xmin, xmax], [ymin, ymax]] - # ul = np.unique(labels) - # - # for i, l in enumerate(ul): - # #cdict = dict(red =[(0., colors[i][0], colors[i][0]), (1., colors[i][0], colors[i][0])], - # # green=[(0., colors[i][0], colors[i][1]), (1., colors[i][1], colors[i][1])], - # # blue =[(0., colors[i][0], colors[i][2]), (1., colors[i][2], colors[i][2])], - # # alpha=[(0., 0., .0), (.5, .5, .5), (1., .5, .5)]) - # #cmap = LinearSegmentedColormap('{}'.format(l), cdict) - # cmap = LinearSegmentedColormap.from_list('cmap_{}'.format(str(l)), [colors[i], colors[i]], 255) - # cmap._init() - # #alphas = .5*(1+scipy.special.erf(np.linspace(-2,2, cmap.N+3)))#np.log(np.linspace(np.exp(0), np.exp(1.), cmap.N+3)) - # alphas = (scipy.special.erf(np.linspace(0,2.4, cmap.N+3)))#np.log(np.linspace(np.exp(0), np.exp(1.), cmap.N+3)) - # cmap._lut[:, -1] = alphas - # print l - # x, y = X[labels==l].T - # - # heatmap, xedges, yedges = np.histogram2d(x, y, bins=300, range=range_) - # #heatmap, xedges, yedges = np.histogram2d(x, y, bins=100) - # - # im = ax.imshow(heatmap, extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]], cmap=cmap, aspect='auto', interpolation='nearest', label=str(l)) - # legend_handles.append(mpatches.Patch(color=colors[i], label=l)) - # ax.set_xlim(xmin, xmax) - # ax.set_ylim(ymin, ymax) - # plt.legend(legend_handles, [l.get_label() for l in legend_handles]) - # plt.draw() - # plt.show() - #======================================================================= - - # create a function which computes the shading of latent space according to the output variance - def plot_function(x): - Xtest_full = np.zeros((x.shape[0], X.shape[1])) - Xtest_full[:, [input_1, input_2]] = x - _, var = model.predict(Xtest_full, **predict_kwargs) - var = var[:, :1] - return np.log(var) - - #Create an IMshow controller that can re-plot the latent space shading at a good resolution - if plot_limits is None: - xmin, ymin = X[:, [input_1, input_2]].min(0) - xmax, ymax = X[:, [input_1, input_2]].max(0) - x_r, y_r = xmax-xmin, ymax-ymin - xmin -= .1*x_r - xmax += .1*x_r - ymin -= .1*y_r - ymax += .1*y_r - else: - try: - xmin, xmax, ymin, ymax = plot_limits - except (TypeError, ValueError) as e: - raise e.__class__("Wrong plot limits: {} given -> need (xmin, xmax, ymin, ymax)".format(plot_limits)) - view = ImshowController(ax, plot_function, - (xmin, ymin, xmax, ymax), - resolution, aspect=aspect, interpolation='bilinear', - cmap=cm.binary, **imshow_kwargs) - - # make sure labels are in order of input: - labels = np.asarray(labels) - ulabels = [] - for lab in labels: - if not lab in ulabels: - ulabels.append(lab) - - marker = itertools.cycle(list(marker)) - - for i, ul in enumerate(ulabels): - if type(ul) is np.string_: - this_label = ul - elif type(ul) is np.int64: - this_label = 'class %i' % ul - else: - this_label = unicode(ul) - m = marker.next() - - index = np.nonzero(labels == ul)[0] - if model.input_dim == 1: - x = X[index, input_1] - y = np.zeros(index.size) - else: - x = X[index, input_1] - y = X[index, input_2] - ax.scatter(x, y, marker=m, s=s, c=Tango.nextMedium(), label=this_label, linewidth=.2, edgecolor='k', alpha=.9) - - ax.set_xlabel('latent dimension %i' % input_1) - ax.set_ylabel('latent dimension %i' % input_2) - - if not np.all(labels == 1.) and legend: - ax.legend(loc=0, numpoints=1) - - ax.grid(b=False) # remove the grid if present, it doesn't look good - ax.set_aspect('auto') # set a nice aspect ratio - - if plot_inducing: - Z = model.Z - ax.scatter(Z[:, input_1], Z[:, input_2], c='w', s=14, marker="^", edgecolor='k', linewidth=.3, alpha=.6) - - ax.set_xlim((xmin, xmax)) - ax.set_ylim((ymin, ymax)) - - try: - fig.canvas.draw() - fig.tight_layout() - fig.canvas.draw() - except Exception as e: - print("Could not invoke tight layout: {}".format(e)) - pass - - if updates: - try: - fig.canvas.show() - except Exception as e: - print("Could not invoke show: {}".format(e)) - #raw_input('Enter to continue') - return view - return ax - -def plot_magnification(model, labels=None, which_indices=None, - resolution=60, ax=None, marker='o', s=40, - fignum=None, plot_inducing=False, legend=True, - plot_limits=None, - aspect='auto', updates=False, mean=True, covariance=True, kern=None): - """ - :param labels: a np.array of size model.num_data containing labels for the points (can be number, strings, etc) - :param resolution: the resolution of the grid on which to evaluate the predictive variance - """ - if ax is None: - fig = pb.figure(num=fignum) - ax = fig.add_subplot(111) - else: - fig = ax.figure - Tango.reset() - - if labels is None: - labels = np.ones(model.num_data) - - input_1, input_2 = most_significant_input_dimensions(model, which_indices) - - #fethch the data points X that we'd like to plot - X = model.X - if isinstance(X, VariationalPosterior): - X = X.mean - else: - X = X - - if X.shape[0] > 1000: - print("Warning: subsampling X, as it has more samples then 1000. X.shape={!s}".format(X.shape)) - subsample = np.random.choice(X.shape[0], size=1000, replace=False) - X = X[subsample] - labels = labels[subsample] - #======================================================================= - # <<>> - # <<>> - # plt.close('all') - # fig, ax = plt.subplots(1,1) - # from GPy.plotting.matplot_dep.dim_reduction_plots import most_significant_input_dimensions - # import matplotlib.patches as mpatches - # i1, i2 = most_significant_input_dimensions(m, None) - # xmin, xmax = 100, -100 - # ymin, ymax = 100, -100 - # legend_handles = [] - # - # X = m.X.mean[:, [i1, i2]] - # X = m.X.variance[:, [i1, i2]] - # - # xmin = X[:,0].min(); xmax = X[:,0].max() - # ymin = X[:,1].min(); ymax = X[:,1].max() - # range_ = [[xmin, xmax], [ymin, ymax]] - # ul = np.unique(labels) - # - # for i, l in enumerate(ul): - # #cdict = dict(red =[(0., colors[i][0], colors[i][0]), (1., colors[i][0], colors[i][0])], - # # green=[(0., colors[i][0], colors[i][1]), (1., colors[i][1], colors[i][1])], - # # blue =[(0., colors[i][0], colors[i][2]), (1., colors[i][2], colors[i][2])], - # # alpha=[(0., 0., .0), (.5, .5, .5), (1., .5, .5)]) - # #cmap = LinearSegmentedColormap('{}'.format(l), cdict) - # cmap = LinearSegmentedColormap.from_list('cmap_{}'.format(str(l)), [colors[i], colors[i]], 255) - # cmap._init() - # #alphas = .5*(1+scipy.special.erf(np.linspace(-2,2, cmap.N+3)))#np.log(np.linspace(np.exp(0), np.exp(1.), cmap.N+3)) - # alphas = (scipy.special.erf(np.linspace(0,2.4, cmap.N+3)))#np.log(np.linspace(np.exp(0), np.exp(1.), cmap.N+3)) - # cmap._lut[:, -1] = alphas - # print l - # x, y = X[labels==l].T - # - # heatmap, xedges, yedges = np.histogram2d(x, y, bins=300, range=range_) - # #heatmap, xedges, yedges = np.histogram2d(x, y, bins=100) - # - # im = ax.imshow(heatmap, extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]], cmap=cmap, aspect='auto', interpolation='nearest', label=str(l)) - # legend_handles.append(mpatches.Patch(color=colors[i], label=l)) - # ax.set_xlim(xmin, xmax) - # ax.set_ylim(ymin, ymax) - # plt.legend(legend_handles, [l.get_label() for l in legend_handles]) - # plt.draw() - # plt.show() - #======================================================================= - - #Create an IMshow controller that can re-plot the latent space shading at a good resolution - if plot_limits is None: - xmin, ymin = X[:, [input_1, input_2]].min(0) - xmax, ymax = X[:, [input_1, input_2]].max(0) - x_r, y_r = xmax-xmin, ymax-ymin - xmin -= .1*x_r - xmax += .1*x_r - ymin -= .1*y_r - ymax += .1*y_r - else: - try: - xmin, xmax, ymin, ymax = plot_limits - except (TypeError, ValueError) as e: - raise e.__class__("Wrong plot limits: {} given -> need (xmin, xmax, ymin, ymax)".format(plot_limits)) - - - def plot_function(x): - Xtest_full = np.zeros((x.shape[0], X.shape[1])) - Xtest_full[:, [input_1, input_2]] = x - mf = model.predict_magnification(Xtest_full, kern=kern, mean=mean, covariance=covariance) - return mf - - view = ImshowController(ax, plot_function, - (xmin, ymin, xmax, ymax), - resolution, aspect=aspect, interpolation='bilinear', - cmap=cm.get_cmap('Greys')) - - # make sure labels are in order of input: - ulabels = [] - for lab in labels: - if not lab in ulabels: - ulabels.append(lab) - - marker = itertools.cycle(list(marker)) - - for i, ul in enumerate(ulabels): - if type(ul) is np.string_: - this_label = ul - elif type(ul) is np.int64: - this_label = 'class %i' % ul - else: - this_label = unicode(ul) - m = marker.next() - - index = np.nonzero(labels == ul)[0] - if model.input_dim == 1: - x = X[index, input_1] - y = np.zeros(index.size) - else: - x = X[index, input_1] - y = X[index, input_2] - ax.scatter(x, y, marker=m, s=s, c=Tango.nextMedium(), label=this_label, linewidth=.2, edgecolor='k', alpha=.9) - - ax.set_xlabel('latent dimension %i' % input_1) - ax.set_ylabel('latent dimension %i' % input_2) - - if not np.all(labels == 1.) and legend: - ax.legend(loc=0, numpoints=1) - - ax.set_xlim((xmin, xmax)) - ax.set_ylim((ymin, ymax)) - - if plot_inducing and hasattr(model, 'Z'): - Z = model.Z - ax.scatter(Z[:, input_1], Z[:, input_2], c='w', s=18, marker="^", edgecolor='k', linewidth=.3, alpha=.7) - - try: - fig.canvas.draw() - fig.tight_layout() - fig.canvas.draw() - except Exception as e: - print("Could not invoke tight layout: {}".format(e)) - pass - - if updates: - try: - fig.canvas.draw() - fig.canvas.show() - except Exception as e: - print("Could not invoke show: {}".format(e)) - #raw_input('Enter to continue') - return view - return ax - - -def plot_steepest_gradient_map(model, fignum=None, ax=None, which_indices=None, labels=None, data_labels=None, data_marker='o', data_s=40, resolution=20, aspect='auto', updates=False, ** kwargs): - - input_1, input_2 = significant_dims = most_significant_input_dimensions(model, which_indices) - - X = np.zeros((resolution ** 2, model.input_dim)) - indices = np.r_[:X.shape[0]] - if labels is None: - labels = range(model.output_dim) - - def plot_function(x): - X[:, significant_dims] = x - dmu_dX = model.dmu_dXnew(X) - argmax = np.argmax(dmu_dX, 1) - return dmu_dX[indices, argmax], np.array(labels)[argmax] - - if ax is None: - fig = pb.figure(num=fignum) - ax = fig.add_subplot(111) - - if data_labels is None: - data_labels = np.ones(model.num_data) - ulabels = [] - for lab in data_labels: - if not lab in ulabels: - ulabels.append(lab) - marker = itertools.cycle(list(data_marker)) - for i, ul in enumerate(ulabels): - if type(ul) is np.string_: - this_label = ul - elif type(ul) is np.int64: - this_label = 'class %i' % ul - else: - this_label = 'class %i' % i - m = marker.next() - index = np.nonzero(data_labels == ul)[0] - x = X[index, input_1] - y = X[index, input_2] - ax.scatter(x, y, marker=m, s=data_s, color=Tango.nextMedium(), label=this_label) - - ax.set_xlabel('latent dimension %i' % input_1) - ax.set_ylabel('latent dimension %i' % input_2) - - controller = ImAnnotateController(ax, - plot_function, - tuple(X.min(0)[:, significant_dims]) + tuple(X.max(0)[:, significant_dims]), - resolution=resolution, - aspect=aspect, - cmap=get_cmap('jet'), - **kwargs) - ax.legend() - ax.figure.tight_layout() - if updates: - pb.show() - clear = raw_input('Enter to continue') - if clear.lower() in 'yes' or clear == '': - controller.deactivate() - return controller.view diff --git a/GPy/plotting/matplot_dep/inference_plots.py b/GPy/plotting/matplot_dep/inference_plots.py deleted file mode 100644 index ab6e5eaf..00000000 --- a/GPy/plotting/matplot_dep/inference_plots.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2012, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - -try: - from matplotlib import pyplot as pb -except: - pass -#import numpy as np -#import Tango -#from base_plots import gpplot, x_frame1D, x_frame2D - - -def plot_optimizer(optimizer): - if optimizer.trace == None: - print("No trace present so I can't plot it. Please check that the optimizer actually supplies a trace.") - else: - pb.figure() - pb.plot(optimizer.trace) - pb.xlabel('Iteration') - pb.ylabel('f(x)') - -def plot_sgd_traces(optimizer): - pb.figure() - pb.subplot(211) - pb.title('Parameters') - for k in optimizer.param_traces.keys(): - pb.plot(optimizer.param_traces[k], label=k) - pb.legend(loc=0) - pb.subplot(212) - pb.title('Objective function') - pb.plot(optimizer.fopt_trace) diff --git a/GPy/plotting/matplot_dep/kernel_plots.py b/GPy/plotting/matplot_dep/kernel_plots.py deleted file mode 100644 index a7026e4f..00000000 --- a/GPy/plotting/matplot_dep/kernel_plots.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright (c) 2012, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - -import numpy as np -from matplotlib import pyplot as pb -from . import Tango -from matplotlib.textpath import TextPath -from matplotlib.transforms import offset_copy -from .base_plots import ax_default - - - -def add_bar_labels(fig, ax, bars, bottom=0): - transOffset = offset_copy(ax.transData, fig=fig, - x=0., y= -2., units='points') - transOffsetUp = offset_copy(ax.transData, fig=fig, - x=0., y=1., units='points') - for bar in bars: - for i, [patch, num] in enumerate(zip(bar.patches, np.arange(len(bar.patches)))): - if len(bottom) == len(bar): b = bottom[i] - else: b = bottom - height = patch.get_height() + b - xi = patch.get_x() + patch.get_width() / 2. - va = 'top' - c = 'w' - t = TextPath((0, 0), "${xi}$".format(xi=xi), rotation=0, ha='center') - transform = transOffset - if patch.get_extents().height <= t.get_extents().height + 5: - va = 'bottom' - c = 'k' - transform = transOffsetUp - ax.text(xi, height, "${xi}$".format(xi=int(num)), color=c, rotation=0, ha='center', va=va, transform=transform) - - ax.set_xticks([]) - - -def plot_bars(fig, ax, x, ard_params, color, name, bottom=0): - return ax.bar(left=x, height=ard_params.view(np.ndarray), width=.8, - bottom=bottom, align='center', - color=color, edgecolor='k', linewidth=1.2, - label=name.replace("_"," ")) - -def plot_ARD(kernel, fignum=None, ax=None, title='', legend=False, filtering=None): - """ - If an ARD kernel is present, plot a bar representation using matplotlib - - :param fignum: figure number of the plot - :param ax: matplotlib axis to plot on - :param title: - title of the plot, - pass '' to not print a title - pass None for a generic title - :param filtering: list of names, which to use for plotting ARD parameters. - Only kernels which match names in the list of names in filtering - will be used for plotting. - :type filtering: list of names to use for ARD plot - """ - fig, ax = ax_default(fignum,ax) - - if title is None: - ax.set_title('ARD parameters, %s kernel' % kernel.name) - else: - ax.set_title(title) - - Tango.reset() - bars = [] - - ard_params = np.atleast_2d(kernel.input_sensitivity(summarize=False)) - bottom = 0 - last_bottom = bottom - - x = np.arange(kernel.input_dim) - - if filtering is None: - filtering = kernel.parameter_names(recursive=False) - - for i in range(ard_params.shape[0]): - if kernel.parameters[i].name in filtering: - c = Tango.nextMedium() - bars.append(plot_bars(fig, ax, x, ard_params[i,:], c, kernel.parameters[i].name, bottom=bottom)) - last_bottom = ard_params[i,:] - bottom += last_bottom - else: - print("filtering out {}".format(kernel.parameters[i].name)) - - ax.set_xlim(-.5, kernel.input_dim - .5) - add_bar_labels(fig, ax, [bars[-1]], bottom=bottom-last_bottom) - - if legend: - if title is '': - mode = 'expand' - if len(bars) > 1: - mode = 'expand' - ax.legend(bbox_to_anchor=(0., 1.02, 1., 1.02), loc=3, - ncol=len(bars), mode=mode, borderaxespad=0.) - fig.tight_layout(rect=(0, 0, 1, .9)) - else: - ax.legend() - return ax - - - -def plot(kernel,x=None, fignum=None, ax=None, title=None, plot_limits=None, resolution=None, **mpl_kwargs): - """ - plot a kernel. - :param x: the value to use for the other kernel argument (kernels are a function of two variables!) - :param fignum: figure number of the plot - :param ax: matplotlib axis to plot on - :param title: the matplotlib title - :param plot_limits: the range over which to plot the kernel - :resolution: the resolution of the lines used in plotting - :mpl_kwargs avalid keyword arguments to pass through to matplotlib (e.g. lw=7) - """ - fig, ax = ax_default(fignum,ax) - - if title is None: - ax.set_title('%s kernel' % kernel.name) - else: - ax.set_title(title) - - - if kernel.input_dim == 1: - if x is None: - x = np.zeros((1, 1)) - else: - x = np.asarray(x) - assert x.size == 1, "The size of the fixed variable x is not 1" - x = x.reshape((1, 1)) - - if plot_limits == None: - xmin, xmax = (x - 5).flatten(), (x + 5).flatten() - elif len(plot_limits) == 2: - xmin, xmax = plot_limits - else: - raise ValueError("Bad limits for plotting") - - Xnew = np.linspace(xmin, xmax, resolution or 201)[:, None] - Kx = kernel.K(Xnew, x) - ax.plot(Xnew, Kx, **mpl_kwargs) - ax.set_xlim(xmin, xmax) - ax.set_xlabel("x") - ax.set_ylabel("k(x,%0.1f)" % x) - - elif kernel.input_dim == 2: - if x is None: - x = np.zeros((1, 2)) - else: - x = np.asarray(x) - assert x.size == 2, "The size of the fixed variable x is not 2" - x = x.reshape((1, 2)) - - if plot_limits is None: - xmin, xmax = (x - 5).flatten(), (x + 5).flatten() - elif len(plot_limits) == 2: - xmin, xmax = plot_limits - else: - raise ValueError("Bad limits for plotting") - - resolution = resolution or 51 - xx, yy = np.mgrid[xmin[0]:xmax[0]:1j * resolution, xmin[1]:xmax[1]:1j * resolution] - Xnew = np.vstack((xx.flatten(), yy.flatten())).T - Kx = kernel.K(Xnew, x) - Kx = Kx.reshape(resolution, resolution).T - ax.contour(xx, yy, Kx, vmin=Kx.min(), vmax=Kx.max(), cmap=pb.cm.jet, **mpl_kwargs) # @UndefinedVariable - ax.set_xlim(xmin[0], xmax[0]) - ax.set_ylim(xmin[1], xmax[1]) - ax.set_xlabel("x1") - ax.set_ylabel("x2") - ax.set_title("k(x1,x2 ; %0.1f,%0.1f)" % (x[0, 0], x[0, 1])) - else: - raise NotImplementedError("Cannot plot a kernel with more than two input dimensions") diff --git a/GPy/plotting/matplot_dep/latent_space_visualizations/__init__.py b/GPy/plotting/matplot_dep/latent_space_visualizations/__init__.py deleted file mode 100644 index 4644261c..00000000 --- a/GPy/plotting/matplot_dep/latent_space_visualizations/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .import controllers diff --git a/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/__init__.py b/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/__init__.py deleted file mode 100644 index f59b71ba..00000000 --- a/GPy/plotting/matplot_dep/latent_space_visualizations/controllers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import axis_event_controller, imshow_controller diff --git a/GPy/plotting/matplot_dep/mapping_plots.py b/GPy/plotting/matplot_dep/mapping_plots.py index fd964a93..c563d392 100644 --- a/GPy/plotting/matplot_dep/mapping_plots.py +++ b/GPy/plotting/matplot_dep/mapping_plots.py @@ -3,7 +3,7 @@ import numpy as np try: - from . import Tango + from GPy.plotting import Tango from matplotlib import pyplot as pb except: pass diff --git a/GPy/plotting/matplot_dep/models_plots.py b/GPy/plotting/matplot_dep/models_plots.py deleted file mode 100644 index 208267c0..00000000 --- a/GPy/plotting/matplot_dep/models_plots.py +++ /dev/null @@ -1,426 +0,0 @@ -# Copyright (c) 2012-2015, GPy authors (see AUTHORS.txt). -# Licensed under the BSD 3-clause license (see LICENSE.txt) - -import numpy as np -from . import Tango -from .base_plots import gpplot, x_frame1D, x_frame2D,gperrors -from ...models.gp_coregionalized_regression import GPCoregionalizedRegression -from ...models.sparse_gp_coregionalized_regression import SparseGPCoregionalizedRegression -from scipy import sparse -from ...core.parameterization.variational import VariationalPosterior -from matplotlib import pyplot as plt - - -def plot_data(model, which_data_rows='all', - which_data_ycols='all', visible_dims=None, - fignum=None, ax=None, data_symbol='kx',mew=1.5): - """ - Plot the training data - - For higher dimensions than two, use fixed_inputs to plot the data points with some of the inputs fixed. - - Can plot only part of the data - using which_data_rows and which_data_ycols. - - :param which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :param which_data_ycols: when the data has several columns (independant outputs), only plot these - :type which_data_rows: 'all' or a list of integers - :param visible_dims: an array specifying the input dimensions to plot (maximum two) - :type visible_dims: a numpy array - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - """ - #deal with optional arguments - if which_data_rows == 'all': - which_data_rows = slice(None) - if which_data_ycols == 'all': - which_data_ycols = np.arange(model.output_dim) - - if ax is None: - fig = plt.figure(num=fignum) - ax = fig.add_subplot(111) - - if hasattr(model, 'has_uncertain_inputs') and model.has_uncertain_inputs(): - X = model.X.mean - X_variance = model.X.variance - else: - X = model.X - X_variance = None - Y = model.Y - - #work out what the inputs are for plotting (1D or 2D) - if visible_dims is None: - visible_dims = np.arange(model.input_dim) - assert visible_dims.size <= 2, "Visible inputs cannot be larger than two" - free_dims = visible_dims - plots = {} - #one dimensional plotting - if len(free_dims) == 1: - plots['dataplot'] = [] - if X_variance is not None: plots['xerrorbar'] = [] - for d in which_data_ycols: - plots['dataplot'].append(ax.plot(X[which_data_rows, free_dims], Y[which_data_rows, d], data_symbol, mew=mew)) - if X_variance is not None: - plots['xerrorbar'] = ax.errorbar(X[which_data_rows, free_dims].flatten(), Y[which_data_rows, d].flatten(), - xerr=2 * np.sqrt(X_variance[which_data_rows, free_dims].flatten()), - ecolor='k', fmt='none', elinewidth=.5, alpha=.5) - - #2D plotting - elif len(free_dims) == 2: - - for d in which_data_ycols: - plots['dataplot'] = ax.scatter(X[which_data_rows, free_dims[0]], X[which_data_rows, free_dims[1]], 40, - Y[which_data_rows, d], cmap=plt.cm.jet, vmin=Y.min(), vmax=Y.max(), linewidth=0.) - - else: - raise NotImplementedError("Cannot define a frame with more than two input dimensions") - return plots - - -def plot_fit(model, plot_limits=None, which_data_rows='all', - which_data_ycols='all', fixed_inputs=[], - levels=20, samples=0, fignum=None, ax=None, resolution=None, - plot_raw=False, - linecol=Tango.colorsHex['darkBlue'],fillcol=Tango.colorsHex['lightBlue'], Y_metadata=None, data_symbol='kx', - apply_link=False, samples_y=0, plot_uncertain_inputs=True, predict_kw=None, plot_training_data=True): - """ - Plot the posterior of the GP. - - In one dimension, the function is plotted with a shaded region identifying two standard deviations. - - In two dimsensions, a contour-plot shows the mean predicted function - - In higher dimensions, use fixed_inputs to plot the GP with some of the inputs fixed. - - Can plot only part of the data and part of the posterior functions - using which_data_rowsm which_data_ycols. - - :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 which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :param which_data_ycols: when the data has several columns (independant outputs), only plot these - :type which_data_rows: 'all' or a list of integers - :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input index i should be set to value v. - :type fixed_inputs: a list of tuples - :param levels: for 2D plotting, the number of contour levels to use is ax is None, create a new figure - :type levels: int - :param samples: the number of a posteriori samples to plot p(f*|y) - :type samples: int - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - :param resolution: the number of intervals to sample the GP on. Defaults to 200 in 1D and 50 (a 50x50 grid) in 2D - :type resolution: int - :param plot_raw: Whether to plot the raw function p(f|y) - :type plot_raw: boolean - :param linecol: color of line to plot. - :type linecol: hex or color - :param fillcol: color of fill - :type fillcol: hex or color - :param apply_link: apply the link function if plotting f (default false), as well as posterior samples if requested - :type apply_link: boolean - :param samples_y: the number of posteriori f samples to plot p(y*|y) - :type samples_y: int - :param plot_uncertain_inputs: plot the uncertainty of the inputs as error bars if they have uncertainty (BGPLVM etc.) - :type plot_uncertain_inputs: boolean - :param predict_kw: keyword args for _raw_predict and predict functions if required - :type predict_kw: dict - :param plot_training_data: whether or not to plot the training points - :type plot_training_data: boolean - """ - #deal with optional arguments - if which_data_rows == 'all': - which_data_rows = slice(None) - if which_data_ycols == 'all': - which_data_ycols = np.arange(model.output_dim) - #if len(which_data_ycols)==0: - #raise ValueError('No data selected for plotting') - if ax is None: - fig = plt.figure(num=fignum) - ax = fig.add_subplot(111) - - if hasattr(model, 'has_uncertain_inputs') and model.has_uncertain_inputs(): - X = model.X.mean - X_variance = model.X.variance - else: - X = model.X - Y = model.Y - if sparse.issparse(Y): Y = Y.todense().view(np.ndarray) - - if hasattr(model, 'Z'): Z = model.Z - - if predict_kw is None: - predict_kw = {} - - #work out what the inputs are for plotting (1D or 2D) - fixed_dims = np.array([i for i,v in fixed_inputs]) - free_dims = np.setdiff1d(np.arange(model.input_dim),fixed_dims) - plots = {} - #one dimensional plotting - if len(free_dims) == 1: - - #define the frame on which to plot - Xnew, xmin, xmax = x_frame1D(X[:,free_dims], plot_limits=plot_limits, resolution=resolution or 200) - Xgrid = np.empty((Xnew.shape[0],model.input_dim)) - Xgrid[:,free_dims] = Xnew - for i,v in fixed_inputs: - Xgrid[:,i] = v - - #make a prediction on the frame and plot it - if plot_raw: - m, v = model._raw_predict(Xgrid, **predict_kw) - if apply_link: - lower = model.likelihood.gp_link.transf(m - 2*np.sqrt(v)) - upper = model.likelihood.gp_link.transf(m + 2*np.sqrt(v)) - #Once transformed this is now the median of the function - m = model.likelihood.gp_link.transf(m) - else: - lower = m - 2*np.sqrt(v) - upper = m + 2*np.sqrt(v) - else: - if isinstance(model,GPCoregionalizedRegression) or isinstance(model,SparseGPCoregionalizedRegression): - extra_data = Xgrid[:,-1:].astype(np.int) - if Y_metadata is None: - Y_metadata = {'output_index': extra_data} - else: - Y_metadata['output_index'] = extra_data - m, v = model.predict(Xgrid, full_cov=False, Y_metadata=Y_metadata, **predict_kw) - fmu, fv = model._raw_predict(Xgrid, full_cov=False, **predict_kw) - lower, upper = model.likelihood.predictive_quantiles(fmu, fv, (2.5, 97.5), Y_metadata=Y_metadata) - - - for d in which_data_ycols: - plots['gpplot'] = gpplot(Xnew, m[:, d], lower[:, d], upper[:, d], ax=ax, edgecol=linecol, fillcol=fillcol) - #if not plot_raw: plots['dataplot'] = ax.plot(X[which_data_rows,free_dims], Y[which_data_rows, d], data_symbol, mew=1.5) - if not plot_raw and plot_training_data: - plots['dataplot'] = plot_data(model=model, which_data_rows=which_data_rows, - visible_dims=free_dims, data_symbol=data_symbol, mew=1.5, ax=ax, fignum=fignum) - - - #optionally plot some samples - if samples: #NOTE not tested with fixed_inputs - Fsim = model.posterior_samples_f(Xgrid, samples) - if apply_link: - Fsim = model.likelihood.gp_link.transf(Fsim) - for fi in Fsim.T: - plots['posterior_samples'] = ax.plot(Xnew, fi[:,None], '#3300FF', linewidth=0.25) - #ax.plot(Xnew, fi[:,None], marker='x', linestyle='--',color=Tango.colorsHex['darkBlue']) #TODO apply this line for discrete outputs. - - if samples_y: #NOTE not tested with fixed_inputs - Ysim = model.posterior_samples(Xgrid, samples_y, Y_metadata=Y_metadata) - for yi in Ysim.T: - plots['posterior_samples_y'] = ax.scatter(Xnew, yi[:,None], s=5, c=Tango.colorsHex['darkBlue'], marker='o', alpha=0.5) - #ax.plot(Xnew, yi[:,None], marker='x', linestyle='--',color=Tango.colorsHex['darkBlue']) #TODO apply this line for discrete outputs. - - - #add error bars for uncertain (if input uncertainty is being modelled) - if hasattr(model,"has_uncertain_inputs") and model.has_uncertain_inputs() and plot_uncertain_inputs: - if plot_raw: - #add error bars for uncertain (if input uncertainty is being modelled), for plot_f - #Hack to plot error bars on latent function, rather than on the data - vs = model.X.mean.values.copy() - for i,v in fixed_inputs: - vs[:,i] = v - m_X, _ = model._raw_predict(vs) - if apply_link: - m_X = model.likelihood.gp_link.transf(m_X) - plots['xerrorbar'] = ax.errorbar(X[which_data_rows, free_dims].flatten(), m_X[which_data_rows, which_data_ycols].flatten(), - xerr=2 * np.sqrt(X_variance[which_data_rows, free_dims].flatten()), - ecolor='k', fmt=None, elinewidth=.5, alpha=.5) - - #set the limits of the plot to some sensible values - try: - ymin, ymax = min(np.append(Y[which_data_rows, which_data_ycols].flatten(), lower)), max(np.append(Y[which_data_rows, which_data_ycols].flatten(), upper)) - if ymin != ymax: - ymin, ymax = ymin - 0.1 * (ymax - ymin), ymax + 0.1 * (ymax - ymin) - ax.set_xlim(xmin, xmax) - ax.set_ylim(ymin, ymax) - except: - # do nothing - # No training data on model - pass - - #add inducing inputs (if a sparse model is used) - if hasattr(model,"Z"): - #Zu = model.Z[:,free_dims] * model._Xscale[:,free_dims] + model._Xoffset[:,free_dims] - if isinstance(model,SparseGPCoregionalizedRegression): - Z = Z[Z[:,-1] == Y_metadata['output_index'],:] - Zu = Z[:,free_dims] - z_height = ax.get_ylim()[0] - plots['inducing_inputs'] = ax.plot(Zu, np.zeros_like(Zu) + z_height, 'r|', mew=1.5, markersize=12) - - - - #2D plotting - elif len(free_dims) == 2: - - #define the frame for plotting on - resolution = resolution or 50 - Xnew, _, _, xmin, xmax = x_frame2D(X[:,free_dims], plot_limits, resolution) - Xgrid = np.empty((Xnew.shape[0],model.input_dim)) - Xgrid[:,free_dims] = Xnew - for i,v in fixed_inputs: - Xgrid[:,i] = v - x, y = np.linspace(xmin[0], xmax[0], resolution), np.linspace(xmin[1], xmax[1], resolution) - - #predict on the frame and plot - if plot_raw: - m, _ = model._raw_predict(Xgrid, **predict_kw) - else: - if isinstance(model,GPCoregionalizedRegression) or isinstance(model,SparseGPCoregionalizedRegression): - extra_data = Xgrid[:,-1:].astype(np.int) - if Y_metadata is None: - Y_metadata = {'output_index': extra_data} - else: - Y_metadata['output_index'] = extra_data - m, v = model.predict(Xgrid, full_cov=False, Y_metadata=Y_metadata, **predict_kw) - for d in which_data_ycols: - m_d = m[:,d].reshape(resolution, resolution).T - plots['contour'] = ax.contour(x, y, m_d, levels, vmin=m.min(), vmax=m.max(), cmap=plt.cm.jet) - #if not plot_raw: plots['dataplot'] = ax.scatter(X[which_data_rows, free_dims[0]], X[which_data_rows, free_dims[1]], 40, Y[which_data_rows, d], cmap=plt.cm.jet, vmin=m.min(), vmax=m.max(), linewidth=0.) - if not plot_raw and plot_training_data: - plots['dataplot'] = ax.scatter(X[which_data_rows, free_dims[0]], X[which_data_rows, free_dims[1]], 40, Y[which_data_rows, d], cmap=plt.cm.jet, vmin=m.min(), vmax=m.max(), linewidth=0.) - - #set the limits of the plot to some sensible values - ax.set_xlim(xmin[0], xmax[0]) - ax.set_ylim(xmin[1], xmax[1]) - - if samples: - warnings.warn("Samples are rather difficult to plot for 2D inputs...") - - #add inducing inputs (if a sparse model is used) - if hasattr(model,"Z"): - #Zu = model.Z[:,free_dims] * model._Xscale[:,free_dims] + model._Xoffset[:,free_dims] - Zu = Z[:,free_dims] - plots['inducing_inputs'] = ax.plot(Zu[:,0], Zu[:,1], 'wo') - - else: - raise NotImplementedError("Cannot define a frame with more than two input dimensions") - return plots - -def plot_fit_f(model, *args, **kwargs): - """ - Plot the GP's view of the world, where the data is normalized and before applying a likelihood. - - All args and kwargs are passed on to models_plots.plot. - """ - kwargs['plot_raw'] = True - plot_fit(model,*args, **kwargs) - -def fixed_inputs(model, non_fixed_inputs, fix_routine='median', as_list=True, X_all=False): - """ - Convenience function for returning back fixed_inputs where the other inputs - are fixed using fix_routine - :param model: model - :type model: Model - :param non_fixed_inputs: dimensions of non fixed inputs - :type non_fixed_inputs: list - :param fix_routine: fixing routine to use, 'mean', 'median', 'zero' - :type fix_routine: string - :param as_list: if true, will return a list of tuples with (dimension, fixed_val) otherwise it will create the corresponding X matrix - :type as_list: boolean - """ - f_inputs = [] - if hasattr(model, 'has_uncertain_inputs') and model.has_uncertain_inputs(): - X = model.X.mean.values.copy() - elif isinstance(model.X, VariationalPosterior): - X = model.X.values.copy() - else: - if X_all: - X = model.X_all.copy() - else: - X = model.X.copy() - for i in range(X.shape[1]): - if i not in non_fixed_inputs: - if fix_routine == 'mean': - f_inputs.append( (i, np.mean(X[:,i])) ) - if fix_routine == 'median': - f_inputs.append( (i, np.median(X[:,i])) ) - else: # set to zero zero - f_inputs.append( (i, 0) ) - if not as_list: - X[:,i] = f_inputs[-1][1] - if as_list: - return f_inputs - else: - return X - - -def plot_errorbars_trainset(model, which_data_rows='all', - which_data_ycols='all', fixed_inputs=[], - fignum=None, ax=None, - linecol='red', data_symbol='kx', - predict_kw=None, plot_training_data=True, **kwargs): - - """ - Plot the posterior error bars corresponding to the training data - - For higher dimensions than two, use fixed_inputs to plot the data points with some of the inputs fixed. - - Can plot only part of the data - using which_data_rows and which_data_ycols. - - :param which_data_rows: which of the training data to plot (default all) - :type which_data_rows: 'all' or a slice object to slice model.X, model.Y - :param which_data_ycols: when the data has several columns (independant outputs), only plot these - :type which_data_rows: 'all' or a list of integers - :param fixed_inputs: a list of tuple [(i,v), (i,v)...], specifying that input index i should be set to value v. - :type fixed_inputs: a list of tuples - :param fignum: figure to plot on. - :type fignum: figure number - :param ax: axes to plot on. - :type ax: axes handle - :param plot_training_data: whether or not to plot the training points - :type plot_training_data: boolean - """ - - #deal with optional arguments - if which_data_rows == 'all': - which_data_rows = slice(None) - if which_data_ycols == 'all': - which_data_ycols = np.arange(model.output_dim) - - if ax is None: - fig = plt.figure(num=fignum) - ax = fig.add_subplot(111) - - X = model.X - Y = model.Y - - if predict_kw is None: - predict_kw = {} - - - #work out what the inputs are for plotting (1D or 2D) - fixed_dims = np.array([i for i,v in fixed_inputs]) - free_dims = np.setdiff1d(np.arange(model.input_dim),fixed_dims) - plots = {} - - #one dimensional plotting - if len(free_dims) == 1: - - m, v = model.predict(X, full_cov=False, Y_metadata=model.Y_metadata, **predict_kw) - fmu, fv = model._raw_predict(X, full_cov=False, **predict_kw) - lower, upper = model.likelihood.predictive_quantiles(fmu, fv, (2.5, 97.5), Y_metadata=model.Y_metadata) - - for d in which_data_ycols: - plots['gperrors'] = gperrors(X, m[:, d], lower[:, d], upper[:, d], edgecol=linecol, ax=ax, fignum=fignum, **kwargs ) - if plot_training_data: - plots['dataplot'] = plot_data(model=model, which_data_rows=which_data_rows, - visible_dims=free_dims, data_symbol=data_symbol, mew=1.5, ax=ax, fignum=fignum) - - - #set the limits of the plot to some sensible values - ymin, ymax = min(np.append(Y[which_data_rows, which_data_ycols].flatten(), lower)), max(np.append(Y[which_data_rows, which_data_ycols].flatten(), upper)) - ymin, ymax = ymin - 0.1 * (ymax - ymin), ymax + 0.1 * (ymax - ymin) - ax.set_xlim(X[:,free_dims].min(), X[:,free_dims].max()) - ax.set_ylim(ymin, ymax) - - - elif len(free_dims) == 2: - raise NotImplementedError("Not implemented yet") - - - else: - raise NotImplementedError("Cannot define a frame with more than two input dimensions") - return plots diff --git a/GPy/plotting/matplot_dep/netpbmfile.py b/GPy/plotting/matplot_dep/netpbmfile.py deleted file mode 100644 index 030bd574..00000000 --- a/GPy/plotting/matplot_dep/netpbmfile.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# netpbmfile.py - -# Copyright (c) 2011-2013, Christoph Gohlke -# Copyright (c) 2011-2013, The Regents of the University of California -# Produced at the Laboratory for Fluorescence Dynamics. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the copyright holders nor the names of any -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -"""Read and write image data from respectively to Netpbm files. - -This implementation follows the Netpbm format specifications at -http://netpbm.sourceforge.net/doc/. No gamma correction is performed. - -The following image formats are supported: PBM (bi-level), PGM (grayscale), -PPM (color), PAM (arbitrary), XV thumbnail (RGB332, read-only). - -:Author: - `Christoph Gohlke `_ - -:Organization: - Laboratory for Fluorescence Dynamics, University of California, Irvine - -:Version: 2013.01.18 - -Requirements ------------- -* `CPython 2.7, 3.2 or 3.3 `_ -* `Numpy 1.7 `_ -* `Matplotlib 1.2 `_ (optional for plotting) - -Examples --------- ->>> im1 = numpy.array([[0, 1],[65534, 65535]], dtype=numpy.uint16) ->>> imsave('_tmp.pgm', im1) ->>> im2 = imread('_tmp.pgm') ->>> assert numpy.all(im1 == im2) - -""" - -from __future__ import division, print_function - -import sys -import re -import math -from copy import deepcopy - -import numpy - -__version__ = '2013.01.18' -__docformat__ = 'restructuredtext en' -__all__ = ['imread', 'imsave', 'NetpbmFile'] - - -def imread(filename, *args, **kwargs): - """Return image data from Netpbm file as numpy array. - - `args` and `kwargs` are arguments to NetpbmFile.asarray(). - - Examples - -------- - >>> image = imread('_tmp.pgm') - - """ - try: - netpbm = NetpbmFile(filename) - image = netpbm.asarray() - finally: - netpbm.close() - return image - - -def imsave(filename, data, maxval=None, pam=False): - """Write image data to Netpbm file. - - Examples - -------- - >>> image = numpy.array([[0, 1],[65534, 65535]], dtype=numpy.uint16) - >>> imsave('_tmp.pgm', image) - - """ - try: - netpbm = NetpbmFile(data, maxval=maxval) - netpbm.write(filename, pam=pam) - finally: - netpbm.close() - - -class NetpbmFile(object): - """Read and write Netpbm PAM, PBM, PGM, PPM, files.""" - - _types = {b'P1': b'BLACKANDWHITE', b'P2': b'GRAYSCALE', b'P3': b'RGB', - b'P4': b'BLACKANDWHITE', b'P5': b'GRAYSCALE', b'P6': b'RGB', - b'P7 332': b'RGB', b'P7': b'RGB_ALPHA'} - - def __init__(self, arg=None, **kwargs): - """Initialize instance from filename, open file, or numpy array.""" - for attr in ('header', 'magicnum', 'width', 'height', 'maxval', - 'depth', 'tupltypes', '_filename', '_fh', '_data'): - setattr(self, attr, None) - if arg is None: - self._fromdata([], **kwargs) - elif isinstance(arg, basestring): - self._fh = open(arg, 'rb') - self._filename = arg - self._fromfile(self._fh, **kwargs) - elif hasattr(arg, 'seek'): - self._fromfile(arg, **kwargs) - self._fh = arg - else: - self._fromdata(arg, **kwargs) - - def asarray(self, copy=True, cache=False, **kwargs): - """Return image data from file as numpy array.""" - data = self._data - if data is None: - data = self._read_data(self._fh, **kwargs) - if cache: - self._data = data - else: - return data - return deepcopy(data) if copy else data - - def write(self, arg, **kwargs): - """Write instance to file.""" - if hasattr(arg, 'seek'): - self._tofile(arg, **kwargs) - else: - with open(arg, 'wb') as fid: - self._tofile(fid, **kwargs) - - def close(self): - """Close open file. Future asarray calls might fail.""" - if self._filename and self._fh: - self._fh.close() - self._fh = None - - def __del__(self): - self.close() - - def _fromfile(self, fh): - """Initialize instance from open file.""" - fh.seek(0) - data = fh.read(4096) - if (len(data) < 7) or not (b'0' < data[1:2] < b'8'): - raise ValueError("Not a Netpbm file:\n%s" % data[:32]) - try: - self._read_pam_header(data) - except Exception: - try: - self._read_pnm_header(data) - except Exception: - raise ValueError("Not a Netpbm file:\n%s" % data[:32]) - - def _read_pam_header(self, data): - """Read PAM header and initialize instance.""" - regroups = re.search( - b"(^P7[\n\r]+(?:(?:[\n\r]+)|(?:#.*)|" - b"(HEIGHT\s+\d+)|(WIDTH\s+\d+)|(DEPTH\s+\d+)|(MAXVAL\s+\d+)|" - b"(?:TUPLTYPE\s+\w+))*ENDHDR\n)", data).groups() - self.header = regroups[0] - self.magicnum = b'P7' - for group in regroups[1:]: - key, value = group.split() - setattr(self, unicode(key).lower(), int(value)) - matches = re.findall(b"(TUPLTYPE\s+\w+)", self.header) - self.tupltypes = [s.split(None, 1)[1] for s in matches] - - def _read_pnm_header(self, data): - """Read PNM header and initialize instance.""" - bpm = data[1:2] in b"14" - regroups = re.search(b"".join(( - b"(^(P[123456]|P7 332)\s+(?:#.*[\r\n])*", - b"\s*(\d+)\s+(?:#.*[\r\n])*", - b"\s*(\d+)\s+(?:#.*[\r\n])*" * (not bpm), - b"\s*(\d+)\s(?:\s*#.*[\r\n]\s)*)")), data).groups() + (1, ) * bpm - self.header = regroups[0] - self.magicnum = regroups[1] - self.width = int(regroups[2]) - self.height = int(regroups[3]) - self.maxval = int(regroups[4]) - self.depth = 3 if self.magicnum in b"P3P6P7 332" else 1 - self.tupltypes = [self._types[self.magicnum]] - - def _read_data(self, fh, byteorder='>'): - """Return image data from open file as numpy array.""" - fh.seek(len(self.header)) - data = fh.read() - dtype = 'u1' if self.maxval < 256 else byteorder + 'u2' - depth = 1 if self.magicnum == b"P7 332" else self.depth - shape = [-1, self.height, self.width, depth] - size = numpy.prod(shape[1:]) - if self.magicnum in b"P1P2P3": - data = numpy.array(data.split(None, size)[:size], dtype) - data = data.reshape(shape) - elif self.maxval == 1: - shape[2] = int(math.ceil(self.width / 8)) - data = numpy.frombuffer(data, dtype).reshape(shape) - data = numpy.unpackbits(data, axis=-2)[:, :, :self.width, :] - else: - data = numpy.frombuffer(data, dtype) - data = data[:size * (data.size // size)].reshape(shape) - if data.shape[0] < 2: - data = data.reshape(data.shape[1:]) - if data.shape[-1] < 2: - data = data.reshape(data.shape[:-1]) - if self.magicnum == b"P7 332": - rgb332 = numpy.array(list(numpy.ndindex(8, 8, 4)), numpy.uint8) - rgb332 *= [36, 36, 85] - data = numpy.take(rgb332, data, axis=0) - return data - - def _fromdata(self, data, maxval=None): - """Initialize instance from numpy array.""" - data = numpy.array(data, ndmin=2, copy=True) - if data.dtype.kind not in "uib": - raise ValueError("not an integer type: %s" % data.dtype) - if data.dtype.kind == 'i' and numpy.min(data) < 0: - raise ValueError("data out of range: %i" % numpy.min(data)) - if maxval is None: - maxval = numpy.max(data) - maxval = 255 if maxval < 256 else 65535 - if maxval < 0 or maxval > 65535: - raise ValueError("data out of range: %i" % maxval) - data = data.astype('u1' if maxval < 256 else '>u2') - self._data = data - if data.ndim > 2 and data.shape[-1] in (3, 4): - self.depth = data.shape[-1] - self.width = data.shape[-2] - self.height = data.shape[-3] - self.magicnum = b'P7' if self.depth == 4 else b'P6' - else: - self.depth = 1 - self.width = data.shape[-1] - self.height = data.shape[-2] - self.magicnum = b'P5' if maxval > 1 else b'P4' - self.maxval = maxval - self.tupltypes = [self._types[self.magicnum]] - self.header = self._header() - - def _tofile(self, fh, pam=False): - """Write Netbm file.""" - fh.seek(0) - fh.write(self._header(pam)) - data = self.asarray(copy=False) - if self.maxval == 1: - data = numpy.packbits(data, axis=-1) - data.tofile(fh) - - def _header(self, pam=False): - """Return file header as byte string.""" - if pam or self.magicnum == b'P7': - header = "\n".join(( - "P7", - "HEIGHT %i" % self.height, - "WIDTH %i" % self.width, - "DEPTH %i" % self.depth, - "MAXVAL %i" % self.maxval, - "\n".join("TUPLTYPE %s" % unicode(i) for i in self.tupltypes), - "ENDHDR\n")) - elif self.maxval == 1: - header = "P4 %i %i\n" % (self.width, self.height) - elif self.depth == 1: - header = "P5 %i %i %i\n" % (self.width, self.height, self.maxval) - else: - header = "P6 %i %i %i\n" % (self.width, self.height, self.maxval) - if sys.version_info[0] > 2: - header = bytes(header, 'ascii') - return header - - def __str__(self): - """Return information about instance.""" - return unicode(self.header) - - -if sys.version_info[0] > 2: - basestring = str - unicode = lambda x: str(x, 'ascii') - -if __name__ == "__main__": - # Show images specified on command line or all images in current directory - from glob import glob - from matplotlib import pyplot - files = sys.argv[1:] if len(sys.argv) > 1 else glob('*.p*m') - for fname in files: - try: - pam = NetpbmFile(fname) - img = pam.asarray(copy=False) - if False: - pam.write('_tmp.pgm.out', pam=True) - img2 = imread('_tmp.pgm.out') - assert numpy.all(img == img2) - imsave('_tmp.pgm.out', img) - img2 = imread('_tmp.pgm.out') - assert numpy.all(img == img2) - pam.close() - except ValueError as e: - print(fname, e) - continue - _shape = img.shape - if img.ndim > 3 or (img.ndim > 2 and img.shape[-1] not in (3, 4)): - img = img[0] - cmap = 'gray' if pam.maxval > 1 else 'binary' - pyplot.imshow(img, cmap, interpolation='nearest') - pyplot.title("%s %s %s %s" % (fname, unicode(pam.magicnum), - _shape, img.dtype)) - pyplot.show() diff --git a/GPy/plotting/matplot_dep/plot_definitions.py b/GPy/plotting/matplot_dep/plot_definitions.py new file mode 100644 index 00000000..a33e6bbe --- /dev/null +++ b/GPy/plotting/matplot_dep/plot_definitions.py @@ -0,0 +1,300 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy.plotting.matplot_dep.plot_definitions nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== +import numpy as np +from matplotlib import pyplot as plt +from ..abstract_plotting_library import AbstractPlottingLibrary +from .. import Tango +from . import defaults +from matplotlib.colors import LinearSegmentedColormap +from .controllers import ImshowController, ImAnnotateController +import itertools +from .util import legend_ontop + +class MatplotlibPlots(AbstractPlottingLibrary): + def __init__(self): + super(MatplotlibPlots, self).__init__() + self._defaults = defaults.__dict__ + + def figure(self, rows=1, cols=1, **kwargs): + fig = plt.figure(**kwargs) + fig.rows = rows + fig.cols = cols + return fig + + def new_canvas(self, figure=None, col=1, row=1, projection='2d', xlabel=None, ylabel=None, zlabel=None, title=None, xlim=None, ylim=None, zlim=None, **kwargs): + if projection == '3d': + from mpl_toolkits.mplot3d import Axes3D + elif projection == '2d': + projection = None + if 'ax' in kwargs: + ax = kwargs.pop('ax') + else: + if 'num' in kwargs and 'figsize' in kwargs: + fig = self.figure(num=kwargs.pop('num'), figsize=kwargs.pop('figsize')) + elif 'num' in kwargs: + fig = self.figure(num=kwargs.pop('num')) + elif 'figsize' in kwargs: + fig = self.figure(figsize=kwargs.pop('figsize')) + else: + fig = self.figure() + + #if hasattr(fig, 'rows') and hasattr(fig, 'cols'): + ax = fig.add_subplot(fig.rows, fig.cols, (col,row), projection=projection) + + if xlim is not None: ax.set_xlim(xlim) + if ylim is not None: ax.set_ylim(ylim) + if xlabel is not None: ax.set_xlabel(xlabel) + if ylabel is not None: ax.set_ylabel(ylabel) + if title is not None: ax.set_title(title) + if projection == '3d': + if zlim is not None: ax.set_zlim(zlim) + if zlabel is not None: ax.set_zlabel(zlabel) + return ax, kwargs + + def add_to_canvas(self, ax, plots, legend=False, title=None, **kwargs): + ax.autoscale_view() + fontdict=dict(family='sans-serif', weight='light', size=9) + if legend is True: + ax.legend(*ax.get_legend_handles_labels()) + elif legend >= 1: + #ax.legend(prop=fontdict) + legend_ontop(ax, ncol=legend, fontdict=fontdict) + if title is not None: ax.figure.suptitle(title) + return ax + + def show_canvas(self, ax, tight_layout=False, **kwargs): + if tight_layout: + ax.figure.tight_layout() + ax.figure.canvas.draw() + return ax.figure + + def scatter(self, ax, X, Y, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, marker='o', **kwargs): + if Z is not None: + return ax.scatter(X, Y, c=color, zs=Z, label=label, marker=marker, **kwargs) + return ax.scatter(X, Y, c=color, label=label, marker=marker, **kwargs) + + def plot(self, ax, X, Y, Z=None, color=None, label=None, **kwargs): + if Z is not None: + return ax.plot(X, Y, color=color, zs=Z, label=label, **kwargs) + return ax.plot(X, Y, color=color, label=label, **kwargs) + + def plot_axis_lines(self, ax, X, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + from matplotlib import transforms + from matplotlib.path import Path + if 'marker' not in kwargs: + kwargs['marker'] = Path([[-.2,0.], [-.2,.5], [0.,1.], [.2,.5], [.2,0.], [-.2,0.]], + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + if 'transform' not in kwargs: + if X.shape[1] == 1: + kwargs['transform'] = transforms.blended_transform_factory(ax.transData, ax.transAxes) + if X.shape[1] == 2: + return ax.scatter(X[:,0], X[:,1], ax.get_zlim()[0], c=color, label=label, **kwargs) + return ax.scatter(X, np.zeros_like(X), c=color, label=label, **kwargs) + + def barplot(self, ax, x, height, width=0.8, bottom=0, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + if 'align' not in kwargs: + kwargs['align'] = 'center' + return ax.bar(left=x, height=height, width=width, + bottom=bottom, label=label, color=color, + **kwargs) + + def xerrorbar(self, ax, X, Y, error, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + if not('linestyle' in kwargs or 'ls' in kwargs): + kwargs['ls'] = 'none' + #if Z is not None: + # return ax.errorbar(X, Y, Z, xerr=error, ecolor=color, label=label, **kwargs) + return ax.errorbar(X, Y, xerr=error, ecolor=color, label=label, **kwargs) + + def yerrorbar(self, ax, X, Y, error, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + if not('linestyle' in kwargs or 'ls' in kwargs): + kwargs['ls'] = 'none' + #if Z is not None: + # return ax.errorbar(X, Y, Z, yerr=error, ecolor=color, label=label, **kwargs) + return ax.errorbar(X, Y, yerr=error, ecolor=color, label=label, **kwargs) + + def imshow(self, ax, X, extent=None, label=None, vmin=None, vmax=None, **imshow_kwargs): + if 'origin' not in imshow_kwargs: + imshow_kwargs['origin'] = 'lower' + #xmin, xmax, ymin, ymax = extent + #xoffset, yoffset = (xmax - xmin) / (2. * X.shape[0]), (ymax - ymin) / (2. * X.shape[1]) + #xmin, xmax, ymin, ymax = extent = xmin-xoffset, xmax+xoffset, ymin-yoffset, ymax+yoffset + return ax.imshow(X, label=label, extent=extent, vmin=vmin, vmax=vmax, **imshow_kwargs) + + def imshow_interact(self, ax, plot_function, extent, label=None, resolution=None, vmin=None, vmax=None, **imshow_kwargs): + if imshow_kwargs is None: imshow_kwargs = {} + if 'origin' not in imshow_kwargs: + imshow_kwargs['origin'] = 'lower' + return ImshowController(ax, plot_function, extent, resolution=resolution, vmin=vmin, vmax=vmax, **imshow_kwargs) + + def annotation_heatmap(self, ax, X, annotation, extent=None, label=None, imshow_kwargs=None, **annotation_kwargs): + if imshow_kwargs is None: imshow_kwargs = {} + if 'origin' not in imshow_kwargs: + imshow_kwargs['origin'] = 'lower' + if ('ha' not in annotation_kwargs) and ('horizontalalignment' not in annotation_kwargs): + annotation_kwargs['ha'] = 'center' + if ('va' not in annotation_kwargs) and ('verticalalignment' not in annotation_kwargs): + annotation_kwargs['va'] = 'center' + imshow = self.imshow(ax, X, extent, label, **imshow_kwargs) + if extent is None: + extent = (0, X.shape[0], 0, X.shape[1]) + xmin, xmax, ymin, ymax = extent + xoffset, yoffset = (xmax - xmin) / (2. * X.shape[0]), (ymax - ymin) / (2. * X.shape[1]) + xlin = np.linspace(xmin, xmax, X.shape[0], endpoint=False) + ylin = np.linspace(ymin, ymax, X.shape[1], endpoint=False) + annotations = [] + for [i, x], [j, y] in itertools.product(enumerate(xlin), enumerate(ylin)): + annotations.append(ax.text(x+xoffset, y+yoffset, "{}".format(annotation[j, i]), **annotation_kwargs)) + return imshow, annotations + + def annotation_heatmap_interact(self, ax, plot_function, extent, label=None, resolution=15, imshow_kwargs=None, **annotation_kwargs): + if imshow_kwargs is None: imshow_kwargs = {} + if 'origin' not in imshow_kwargs: + imshow_kwargs['origin'] = 'lower' + return ImAnnotateController(ax, plot_function, extent, resolution=resolution, imshow_kwargs=imshow_kwargs or {}, **annotation_kwargs) + + def contour(self, ax, X, Y, C, levels=20, label=None, **kwargs): + return ax.contour(X, Y, C, levels=np.linspace(C.min(), C.max(), levels), label=label, **kwargs) + + def surface(self, ax, X, Y, Z, color=None, label=None, **kwargs): + return ax.plot_surface(X, Y, Z, label=label, **kwargs) + + def fill_between(self, ax, X, lower, upper, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + return ax.fill_between(X, lower, upper, facecolor=color, label=label, **kwargs) + + def fill_gradient(self, canvas, X, percentiles, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + ax = canvas + plots = [] + + if 'edgecolors' not in kwargs: + kwargs['edgecolors'] = 'none' + + if 'facecolors' in kwargs: + color = kwargs.pop('facecolors') + + if 'array' in kwargs: + array = kwargs.pop('array') + else: + array = 1.-np.abs(np.linspace(-.97, .97, len(percentiles)-1)) + + if 'alpha' in kwargs: + alpha = kwargs.pop('alpha') + else: + alpha = .8 + + if 'cmap' in kwargs: + cmap = kwargs.pop('cmap') + else: + cmap = LinearSegmentedColormap.from_list('WhToColor', (color, color), N=array.size) + cmap._init() + cmap._lut[:-3, -1] = alpha*array + + kwargs['facecolors'] = [cmap(i) for i in np.linspace(0,1,cmap.N)] + + # pop where from kwargs + where = kwargs.pop('where') if 'where' in kwargs else None + # pop interpolate, which we actually do not do here! + if 'interpolate' in kwargs: kwargs.pop('interpolate') + + def pairwise(iterable): + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + from itertools import tee + #try: + # from itertools import izip as zip + #except ImportError: + # pass + a, b = tee(iterable) + next(b, None) + return zip(a, b) + + polycol = [] + for y1, y2 in pairwise(percentiles): + import matplotlib.mlab as mlab + # Handle united data, such as dates + ax._process_unit_info(xdata=X, ydata=y1) + ax._process_unit_info(ydata=y2) + # Convert the arrays so we can work with them + from numpy import ma + x = ma.masked_invalid(ax.convert_xunits(X)) + y1 = ma.masked_invalid(ax.convert_yunits(y1)) + y2 = ma.masked_invalid(ax.convert_yunits(y2)) + + if y1.ndim == 0: + y1 = np.ones_like(x) * y1 + if y2.ndim == 0: + y2 = np.ones_like(x) * y2 + + if where is None: + where = np.ones(len(x), np.bool) + else: + where = np.asarray(where, np.bool) + + if not (x.shape == y1.shape == y2.shape == where.shape): + raise ValueError("Argument dimensions are incompatible") + + from functools import reduce + mask = reduce(ma.mask_or, [ma.getmask(a) for a in (x, y1, y2)]) + if mask is not ma.nomask: + where &= ~mask + + polys = [] + for ind0, ind1 in mlab.contiguous_regions(where): + xslice = x[ind0:ind1] + y1slice = y1[ind0:ind1] + y2slice = y2[ind0:ind1] + + if not len(xslice): + continue + + N = len(xslice) + p = np.zeros((2 * N + 2, 2), np.float) + + # the purpose of the next two lines is for when y2 is a + # scalar like 0 and we want the fill to go all the way + # down to 0 even if none of the y1 sample points do + start = xslice[0], y2slice[0] + end = xslice[-1], y2slice[-1] + + p[0] = start + p[N + 1] = end + + p[1:N + 1, 0] = xslice + p[1:N + 1, 1] = y1slice + p[N + 2:, 0] = xslice[::-1] + p[N + 2:, 1] = y2slice[::-1] + + polys.append(p) + polycol.extend(polys) + from matplotlib.collections import PolyCollection + if 'zorder' not in kwargs: + kwargs['zorder'] = 0 + plots.append(PolyCollection(polycol, **kwargs)) + ax.add_collection(plots[-1], autolim=True) + ax.autoscale_view() + return plots diff --git a/GPy/plotting/matplot_dep/util.py b/GPy/plotting/matplot_dep/util.py new file mode 100644 index 00000000..2dd6af85 --- /dev/null +++ b/GPy/plotting/matplot_dep/util.py @@ -0,0 +1,119 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy.plotting.matplot_dep.util nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== + +from matplotlib import pyplot as plt +import numpy as np + +def legend_ontop(ax, mode='expand', ncol=3, fontdict=None): + from mpl_toolkits.axes_grid1 import make_axes_locatable + handles, labels = ax.get_legend_handles_labels() + divider = make_axes_locatable(ax) + cax = divider.append_axes("top", "5%", pad=0) + lgd = cax.legend(handles, labels, bbox_to_anchor=(0., 0., 1., 1.), loc=3, + ncol=ncol, mode=mode, borderaxespad=0., prop=fontdict or {}) + cax.set_axis_off() + #lgd = cax.legend(bbox_to_anchor=(0., 1.02, 1., 1.02), loc=3, + # ncol=ncol, mode=mode, borderaxespad=0., prop=fontdict or {}) + return lgd + +def removeRightTicks(ax=None): + ax = ax or plt.gca() + for i, line in enumerate(ax.get_yticklines()): + if i%2 == 1: # odd indices + line.set_visible(False) + +def removeUpperTicks(ax=None): + ax = ax or plt.gca() + for i, line in enumerate(ax.get_xticklines()): + if i%2 == 1: # odd indices + line.set_visible(False) + +def fewerXticks(ax=None,divideby=2): + ax = ax or plt.gca() + ax.set_xticks(ax.get_xticks()[::divideby]) + +def align_subplots(N,M,xlim=None, ylim=None): + """make all of the subplots have the same limits, turn off unnecessary ticks""" + #find sensible xlim,ylim + if xlim is None: + xlim = [np.inf,-np.inf] + for i in range(N*M): + plt.subplot(N,M,i+1) + xlim[0] = min(xlim[0],plt.xlim()[0]) + xlim[1] = max(xlim[1],plt.xlim()[1]) + if ylim is None: + ylim = [np.inf,-np.inf] + for i in range(N*M): + plt.subplot(N,M,i+1) + ylim[0] = min(ylim[0],plt.ylim()[0]) + ylim[1] = max(ylim[1],plt.ylim()[1]) + + for i in range(N*M): + plt.subplot(N,M,i+1) + plt.xlim(xlim) + plt.ylim(ylim) + if (i)%M: + plt.yticks([]) + else: + removeRightTicks() + if i<(M*(N-1)): + plt.xticks([]) + else: + removeUpperTicks() + +def align_subplot_array(axes,xlim=None, ylim=None): + """ + Make all of the axes in the array hae the same limits, turn off unnecessary ticks + use plt.subplots() to get an array of axes + """ + #find sensible xlim,ylim + if xlim is None: + xlim = [np.inf,-np.inf] + for ax in axes.flatten(): + xlim[0] = min(xlim[0],ax.get_xlim()[0]) + xlim[1] = max(xlim[1],ax.get_xlim()[1]) + if ylim is None: + ylim = [np.inf,-np.inf] + for ax in axes.flatten(): + ylim[0] = min(ylim[0],ax.get_ylim()[0]) + ylim[1] = max(ylim[1],ax.get_ylim()[1]) + + N,M = axes.shape + for i,ax in enumerate(axes.flatten()): + ax.set_xlim(xlim) + ax.set_ylim(ylim) + if (i)%M: + ax.set_yticks([]) + else: + removeRightTicks(ax) + if i<(M*(N-1)): + ax.set_xticks([]) + else: + removeUpperTicks(ax) \ No newline at end of file diff --git a/GPy/plotting/matplot_dep/visualize.py b/GPy/plotting/matplot_dep/visualize.py index a9522d90..c5d2fe14 100644 --- a/GPy/plotting/matplot_dep/visualize.py +++ b/GPy/plotting/matplot_dep/visualize.py @@ -1,11 +1,10 @@ -import matplotlib.pyplot as plt -from mpl_toolkits.mplot3d import Axes3D -import GPy import numpy as np -import matplotlib as mpl import time from ...core.parameterization.variational import VariationalPosterior try: + import matplotlib.pyplot as plt + import matplotlib as mpl + from mpl_toolkits.mplot3d import Axes3D import visual visual_available = True diff --git a/GPy/kern/_src/__init__.py b/GPy/plotting/plotly_dep/__init__.py similarity index 100% rename from GPy/kern/_src/__init__.py rename to GPy/plotting/plotly_dep/__init__.py diff --git a/GPy/plotting/plotly_dep/defaults.py b/GPy/plotting/plotly_dep/defaults.py new file mode 100644 index 00000000..faf343b0 --- /dev/null +++ b/GPy/plotting/plotly_dep/defaults.py @@ -0,0 +1,76 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== + +from .. import Tango +from plotly.graph_objs import Line + +''' +This file is for defaults for the gpy plot, specific to the plotting library. + +Create a kwargs dictionary with the right name for the plotting function +you are implementing. If you do not provide defaults, the default behaviour of +the plotting library will be used. + +In the code, always ise plotting.gpy_plots.defaults to get the defaults, as +it gives back an empty default, when defaults are not defined. +''' + +# Data plots: +data_1d = dict(marker_kwargs=dict(), marker='x', color='black') +data_2d = dict(marker='o', cmap='Hot', marker_kwargs=dict(opacity=1., size='5', line=Line(width=.5, color='black'))) +inducing_1d = dict(color=Tango.colorsHex['darkRed']) +inducing_2d = dict(marker_kwargs=dict(size='5', opacity=.7, line=Line(width=.5, color='black')), opacity=.7, color='white', marker='star-triangle-up') +inducing_3d = dict(marker_kwargs=dict(symbol='diamond', size='5', opacity=.7, line=Line(width=.1, color='black')), color='#F5F5F5') +xerrorbar = dict(color='black', error_kwargs=dict(thickness=.5), opacity=.5) +yerrorbar = dict(color=Tango.colorsHex['darkRed'], error_kwargs=dict(thickness=.5), opacity=.5) +# +# # GP plots: +meanplot_1d = dict(color=Tango.colorsHex['mediumBlue'], line_kwargs=dict(width=2)) +meanplot_2d = dict(colorscale='Hot') +meanplot_3d = dict(colorscale='Hot', opacity=.9) +samples_1d = dict(color=Tango.colorsHex['mediumBlue'], line_kwargs=dict(width=.3)) +samples_3d = dict(cmap='Hot', opacity=.5) +confidence_interval = dict(mode='lines', line_kwargs=dict(color=Tango.colorsHex['darkBlue'], width=.4), + color=Tango.colorsHex['lightBlue'], opacity=.3) +# density = dict(alpha=.5, color=Tango.colorsHex['lightBlue']) +# +# # GPLVM plots: +# data_y_1d = dict(linewidth=0, cmap='RdBu', s=40) +# data_y_1d_plot = dict(color='k', linewidth=1.5) +# +# # Kernel plots: +ard = dict(linewidth=1.2, barmode='stack') +# +# # Input plots: +latent = dict(colorscale='Greys', reversescale=True, zsmooth='best') +gradient = dict(colorscale='RdBu', opacity=.7) +magnification = dict(colorscale='Greys', zsmooth='best', reversescale=True) +latent_scatter = dict(marker_kwargs=dict(size='15', opacity=.7)) +# annotation = dict(fontdict=dict(family='sans-serif', weight='light', fontsize=9), zorder=.3, alpha=.7) \ No newline at end of file diff --git a/GPy/plotting/plotly_dep/plot_definitions.py b/GPy/plotting/plotly_dep/plot_definitions.py new file mode 100644 index 00000000..613cdf4c --- /dev/null +++ b/GPy/plotting/plotly_dep/plot_definitions.py @@ -0,0 +1,312 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy.plotting.matplot_dep.plot_definitions nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== +import numpy as np +from ..abstract_plotting_library import AbstractPlottingLibrary +from .. import Tango +from . import defaults +from plotly import tools +from plotly import plotly as py +from plotly.graph_objs import Scatter, Scatter3d, Line,\ + Marker, ErrorX, ErrorY, Bar, Heatmap, Trace,\ + Annotations, Annotation, Contour, Font, Surface +from plotly.exceptions import PlotlyDictKeyError + +SYMBOL_MAP = { + 'o': 'dot', + 'v': 'triangle-down', + '^': 'triangle-up', + '<': 'triangle-left', + '>': 'triangle-right', + 's': 'square', + '+': 'cross', + 'x': 'x', + '*': 'x', # no star yet in plotly!! + 'D': 'diamond', + 'd': 'diamond', +} + +class PlotlyPlots(AbstractPlottingLibrary): + def __init__(self): + super(PlotlyPlots, self).__init__() + self._defaults = defaults.__dict__ + self.current_states = dict() + + def figure(self, rows=1, cols=1, specs=None, is_3d=False, **kwargs): + if specs is None: + specs = [[{'is_3d': is_3d}]*cols]*rows + figure = tools.make_subplots(rows, cols, specs=specs, **kwargs) + return figure + + def new_canvas(self, figure=None, row=1, col=1, projection='2d', + xlabel=None, ylabel=None, zlabel=None, + title=None, xlim=None, + ylim=None, zlim=None, **kwargs): + #if 'filename' not in kwargs: + # print('PlotlyWarning: filename was not given, this may clutter your plotly workspace') + # filename = None + #else: + # filename = kwargs.pop('filename') + if figure is None: + figure = self.figure(is_3d=projection=='3d') + figure.layout.font = Font(family="Raleway, sans-serif") + if projection == '3d': + figure.layout.legend.x=.5 + figure.layout.legend.bgcolor='#DCDCDC' + return (figure, row, col), kwargs + + def add_to_canvas(self, canvas, traces, legend=False, **kwargs): + figure, row, col = canvas + def append_annotation(a, xref, yref): + if 'xref' not in a: + a['xref'] = xref + if 'yref' not in a: + a['yref'] = yref + figure.layout.annotations.append(a) + def append_trace(t, row, col): + figure.append_trace(t, row, col) + def recursive_append(traces): + if isinstance(traces, Annotations): + xref, yref = figure._grid_ref[row-1][col-1] + for a in traces: + append_annotation(a, xref, yref) + elif isinstance(traces, (Trace)): + try: + append_trace(traces, row, col) + except PlotlyDictKeyError: + # Its a dictionary of plots: + for t in traces: + recursive_append(traces[t]) + elif isinstance(traces, (dict)): + for t in traces: + recursive_append(traces[t]) + elif isinstance(traces, (tuple, list)): + for t in traces: + recursive_append(t) + recursive_append(traces) + figure.layout['showlegend'] = legend + return canvas + + def show_canvas(self, canvas, filename=None, **kwargs): + figure, _, _ = canvas + if len(figure.data) == 0: + # add mock data + figure.append_trace(Scatter(x=[], y=[], name='', showlegend=False), 1, 1) + from ..gpy_plot.plot_util import in_ipynb + if in_ipynb(): + return py.iplot(figure, filename=filename)#self.current_states[hex(id(figure))]['filename']) + else: + return py.plot(figure, filename=filename)#self.current_states[hex(id(figure))]['filename']) + + def scatter(self, ax, X, Y, Z=None, color=Tango.colorsHex['mediumBlue'], cmap=None, label=None, marker='o', marker_kwargs=None, **kwargs): + try: + marker = SYMBOL_MAP[marker] + except: + #not matplotlib marker + pass + marker_kwargs.setdefault('symbol', marker) + if Z is not None: + return Scatter3d(x=X, y=Y, z=Z, mode='markers', + showlegend=label is not None, + marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}), + name=label, **kwargs) + return Scatter(x=X, y=Y, mode='markers', showlegend=label is not None, + marker=Marker(color=color, colorscale=cmap, **marker_kwargs or {}), + name=label, **kwargs) + + def plot(self, ax, X, Y, Z=None, color=None, label=None, line_kwargs=None, **kwargs): + if 'mode' not in kwargs: + kwargs['mode'] = 'lines' + if Z is not None: + return Scatter3d(x=X, y=Y, z=Z, showlegend=label is not None, line=Line(color=color, **line_kwargs or {}), name=label, **kwargs) + return Scatter(x=X, y=Y, showlegend=label is not None, line=Line(color=color, **line_kwargs or {}), name=label, **kwargs) + + def plot_axis_lines(self, ax, X, color=Tango.colorsHex['mediumBlue'], label=None, marker_kwargs=None, **kwargs): + if X.shape[1] == 1: + annotations = Annotations() + for i, row in enumerate(X): + annotations.append( + Annotation( + text='', + x=row[0], y=0, + yref='paper', + ax=0, ay=20, + arrowhead=2, + arrowsize=1, + arrowwidth=2, + arrowcolor=color, + showarrow=True, + #showlegend=i==0, + #label=label, + )) + return annotations + elif X.shape[1] == 2: + marker_kwargs.setdefault('symbol', 'diamond') + opacity = kwargs.pop('opacity', .8) + return Scatter3d(x=X[:, 0], y=X[:, 1], z=np.zeros(X.shape[0]), + mode='markers', + projection=dict(z=dict(show=True, opacity=opacity)), + marker=Marker(color=color, **marker_kwargs or {}), + opacity=0, + name=label, + showlegend=label is not None, **kwargs) + + def barplot(self, canvas, x, height, width=0.8, bottom=0, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + figure, _, _ = canvas + if 'barmode' in kwargs: + figure.layout['barmode'] = kwargs.pop('barmode') + return Bar(x=x, y=height, marker=Marker(color=color), name=label) + + def xerrorbar(self, ax, X, Y, error, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, error_kwargs=None, **kwargs): + error_kwargs = error_kwargs or {} + if (error.shape[0] == 2) and (error.ndim == 2): + error_kwargs.update(dict(array=error[1], arrayminus=error[0], symmetric=False)) + else: + error_kwargs.update(dict(array=error, symmetric=True)) + if Z is not None: + return Scatter3d(x=X, y=Y, z=Z, mode='markers', + error_x=ErrorX(color=color, **error_kwargs or {}), + marker=Marker(size='0'), name=label, + showlegend=label is not None, **kwargs) + return Scatter(x=X, y=Y, mode='markers', + error_x=ErrorX(color=color, **error_kwargs or {}), + marker=Marker(size='0'), name=label, + showlegend=label is not None, + **kwargs) + + def yerrorbar(self, ax, X, Y, error, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, error_kwargs=None, **kwargs): + error_kwargs = error_kwargs or {} + if (error.shape[0] == 2) and (error.ndim == 2): + error_kwargs.update(dict(array=error[1], arrayminus=error[0], symmetric=False)) + else: + error_kwargs.update(dict(array=error, symmetric=True)) + if Z is not None: + return Scatter3d(x=X, y=Y, z=Z, mode='markers', + error_y=ErrorY(color=color, **error_kwargs or {}), + marker=Marker(size='0'), name=label, + showlegend=label is not None, **kwargs) + return Scatter(x=X, y=Y, mode='markers', + error_y=ErrorY(color=color, **error_kwargs or {}), + marker=Marker(size='0'), name=label, + showlegend=label is not None, + **kwargs) + + def imshow(self, ax, X, extent=None, label=None, vmin=None, vmax=None, **imshow_kwargs): + if not 'showscale' in imshow_kwargs: + imshow_kwargs['showscale'] = False + return Heatmap(z=X, name=label, + x0=extent[0], dx=float(extent[1]-extent[0])/(X.shape[0]-1), + y0=extent[2], dy=float(extent[3]-extent[2])/(X.shape[1]-1), + zmin=vmin, zmax=vmax, + showlegend=label is not None, + hoverinfo='z', + **imshow_kwargs) + + def imshow_interact(self, ax, plot_function, extent=None, label=None, resolution=None, vmin=None, vmax=None, **imshow_kwargs): + # TODO stream interaction? + super(PlotlyPlots, self).imshow_interact(ax, plot_function) + + def annotation_heatmap(self, ax, X, annotation, extent=None, label='Gradient', imshow_kwargs=None, **annotation_kwargs): + imshow_kwargs.setdefault('label', label) + imshow_kwargs.setdefault('showscale', True) + imshow = self.imshow(ax, X, extent, **imshow_kwargs) + X = X-X.min() + X /= X.max()/2. + X -= 1 + x = np.linspace(extent[0], extent[1], X.shape[0]) + y = np.linspace(extent[2], extent[3], X.shape[1]) + annotations = Annotations() + for n, row in enumerate(annotation): + for m, val in enumerate(row): + var = X[n][m] + annotations.append( + Annotation( + text=str(val), + x=x[m], y=y[n], + xref='x1', yref='y1', + font=dict(color='white' if np.abs(var) > 0.8 else 'black', size=10), + opacity=.5, + showarrow=False, + hoverinfo='x')) + return imshow, annotations + + def annotation_heatmap_interact(self, ax, plot_function, extent, label=None, resolution=15, imshow_kwargs=None, **annotation_kwargs): + super(PlotlyPlots, self).annotation_heatmap_interact(ax, plot_function, extent) + + def contour(self, ax, X, Y, C, levels=20, label=None, **kwargs): + return Contour(x=X, y=Y, z=C, + #ncontours=levels, contours=Contours(start=C.min(), end=C.max(), size=(C.max()-C.min())/levels), + name=label, **kwargs) + + def surface(self, ax, X, Y, Z, color=None, label=None, **kwargs): + return Surface(x=X, y=Y, z=Z, name=label, showlegend=label is not None, **kwargs) + + def fill_between(self, ax, X, lower, upper, color=Tango.colorsHex['mediumBlue'], label=None, line_kwargs=None, **kwargs): + if not 'line' in kwargs: + kwargs['line'] = Line(**line_kwargs or {}) + else: + kwargs['line'].update(line_kwargs or {}) + if color.startswith('#'): + fcolor = 'rgba({c[0]}, {c[1]}, {c[2]}, {alpha})'.format(c=Tango.hex2rgb(color), alpha=kwargs.get('opacity', 1.0)) + else: fcolor = color + u = Scatter(x=X, y=upper, fillcolor=fcolor, showlegend=label is not None, name=label, fill='tonextx', legendgroup='{}_fill_({},{})'.format(label, ax[1], ax[2]), **kwargs) + #fcolor = '{}, {alpha})'.format(','.join(fcolor.split(',')[:-1]), alpha=0.0) + l = Scatter(x=X, y=lower, fillcolor=fcolor, showlegend=False, name=label, legendgroup='{}_fill_({},{})'.format(label, ax[1], ax[2]), **kwargs) + return l, u + + def fill_gradient(self, canvas, X, percentiles, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): + if color.startswith('#'): + colarray = Tango.hex2rgb(color) + opacity = .9 + else: + colarray = map(float(color.strip(')').split('(')[1])) + if len(colarray) == 4: + colarray, opacity = colarray[:3] ,colarray[3] + + alpha = opacity*(1.-np.abs(np.linspace(-1,1,len(percentiles)-1))) + + def pairwise(iterable): + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + from itertools import tee + a, b = tee(iterable) + next(b, None) + return zip(a, b) + + polycol = [] + for i, y1, a in zip(range(len(percentiles)), percentiles, alpha): + fcolor = 'rgba({}, {}, {}, {alpha})'.format(*colarray, alpha=a) + if i == len(percentiles)/2: + polycol.append(Scatter(x=X, y=y1, fillcolor=fcolor, showlegend=True, + name=label, line=Line(width=0, smoothing=0), mode='none', fill='tonextx', + legendgroup='density', hoverinfo='none', **kwargs)) + else: + polycol.append(Scatter(x=X, y=y1, fillcolor=fcolor, showlegend=False, + name=None, line=Line(width=1, smoothing=0, color=fcolor), mode='none', fill='tonextx', + legendgroup='density', hoverinfo='none', **kwargs)) + return polycol diff --git a/GPy/testing/inference_tests.py b/GPy/testing/inference_tests.py index c1fce8b9..92def798 100644 --- a/GPy/testing/inference_tests.py +++ b/GPy/testing/inference_tests.py @@ -13,72 +13,39 @@ import GPy class InferenceXTestCase(unittest.TestCase): def genData(self): - np.random.seed(1) - D1,D2,N = 12,12,50 + np.random.seed(1111) + Ylist = GPy.examples.dimensionality_reduction._simulate_matern(5, 1, 1, 10, 3, False)[0] + return Ylist[0] - x = np.linspace(0, 4 * np.pi, N)[:, None] - s1 = np.vectorize(lambda x: np.sin(x)) - s2 = np.vectorize(lambda x: np.cos(x)**2) - s3 = np.vectorize(lambda x:-np.exp(-np.cos(2 * x))) - sS = np.vectorize(lambda x: np.cos(x)) - - s1 = s1(x) - s2 = s2(x) - s3 = s3(x) - sS = sS(x) - - s1 -= s1.mean(); s1 /= s1.std(0) - s2 -= s2.mean(); s2 /= s2.std(0) - s3 -= s3.mean(); s3 /= s3.std(0) - sS -= sS.mean(); sS /= sS.std(0) - - S1 = np.hstack([s1, sS]) - S2 = np.hstack([s3, sS]) - - P1 = np.random.randn(S1.shape[1], D1) - P2 = np.random.randn(S2.shape[1], D2) - - Y1 = S1.dot(P1) - Y2 = S2.dot(P2) - - Y1 += .01 * np.random.randn(*Y1.shape) - Y2 += .01 * np.random.randn(*Y2.shape) - - Y1 -= Y1.mean(0) - Y2 -= Y2.mean(0) - Y1 /= Y1.std(0) - Y2 /= Y2.std(0) - - slist = [s1, s2, s3, sS] - slist_names = ["s1", "s2", "s3", "sS"] - Ylist = [Y1, Y2] - - return Ylist - - def test_inferenceX_BGPLVM(self): + def test_inferenceX_BGPLVM_Linear(self): Ys = self.genData() - m = GPy.models.BayesianGPLVM(Ys[0],5,kernel=GPy.kern.Linear(5,ARD=True)) + m = GPy.models.BayesianGPLVM(Ys,3,kernel=GPy.kern.Linear(3,ARD=True)) + m.optimize() + x, mi = m.infer_newX(m.Y, optimize=True) + np.testing.assert_array_almost_equal(m.X.mean, mi.X.mean, decimal=2) + np.testing.assert_array_almost_equal(m.X.variance, mi.X.variance, decimal=2) - x,mi = m.infer_newX(m.Y, optimize=False) - self.assertTrue(mi.checkgrad()) - - m.optimize(max_iters=10000) - x, mi = m.infer_newX(m.Y) - - print(m.X.mean - mi.X.mean) - self.assertTrue(np.allclose(m.X.mean, mi.X.mean, rtol=1e-4, atol=1e-4)) - self.assertTrue(np.allclose(m.X.variance, mi.X.variance, rtol=1e-4, atol=1e-4)) - - def test_inferenceX_GPLVM(self): + def test_inferenceX_BGPLVM_RBF(self): Ys = self.genData() - m = GPy.models.GPLVM(Ys[0],3,kernel=GPy.kern.RBF(3,ARD=True)) + m = GPy.models.BayesianGPLVM(Ys,3,kernel=GPy.kern.RBF(3,ARD=True)) + m.optimize() + x, mi = m.infer_newX(m.Y, optimize=True) + np.testing.assert_array_almost_equal(m.X.mean, mi.X.mean, decimal=2) + np.testing.assert_array_almost_equal(m.X.variance, mi.X.variance, decimal=2) - x,mi = m.infer_newX(m.Y, optimize=False) - self.assertTrue(mi.checkgrad()) + def test_inferenceX_GPLVM_Linear(self): + Ys = self.genData() + m = GPy.models.GPLVM(Ys,3,kernel=GPy.kern.Linear(3,ARD=True)) + m.optimize() + x, mi = m.infer_newX(m.Y, optimize=True) + np.testing.assert_array_almost_equal(m.X, mi.X, decimal=2) -# m.optimize(max_iters=10000) -# x,mi = m.infer_newX(m.Y) -# self.assertTrue(np.allclose(m.X, x)) + def test_inferenceX_GPLVM_RBF(self): + Ys = self.genData() + m = GPy.models.GPLVM(Ys,3,kernel=GPy.kern.RBF(3,ARD=True)) + m.optimize() + x, mi = m.infer_newX(m.Y, optimize=True) + np.testing.assert_array_almost_equal(m.X, mi.X, decimal=2) if __name__ == "__main__": diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index 1fd92d98..e81ce2cf 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -346,6 +346,10 @@ class KernelTestsMiscellaneous(unittest.TestCase): self.assertTrue(np.allclose(self.sumkern.K(self.X, which_parts=[self.linear, self.rbf]), self.linear.K(self.X)+self.rbf.K(self.X))) self.assertTrue(np.allclose(self.sumkern.K(self.X, which_parts=self.sumkern.parts[0]), self.rbf.K(self.X))) + def test_active_dims(self): + np.testing.assert_array_equal(self.sumkern.active_dims, [0,1,2,3,7,9]) + np.testing.assert_array_equal(self.sumkern._all_dims_active, range(10)) + class KernelTestsNonContinuous(unittest.TestCase): def setUp(self): N0 = 3 diff --git a/GPy/testing/likelihood_tests.py b/GPy/testing/likelihood_tests.py index 1f634848..de347192 100644 --- a/GPy/testing/likelihood_tests.py +++ b/GPy/testing/likelihood_tests.py @@ -559,36 +559,29 @@ class TestNoiseModels(object): @with_setup(setUp, tearDown) def t_laplace_fit_rbf_white(self, model, X, Y, f, Y_metadata, step, param_vals, param_names, constraints): print("\n{}".format(inspect.stack()[0][3])) + np.random.seed(111) #Normalize Y = Y/Y.max() - white_var = 1e-5 + kernel = GPy.kern.RBF(X.shape[1]) + GPy.kern.White(X.shape[1]) laplace_likelihood = GPy.inference.latent_function_inference.Laplace() m = GPy.core.GP(X.copy(), Y.copy(), kernel, likelihood=model, Y_metadata=Y_metadata, inference_method=laplace_likelihood) - m['.*white'].constrain_fixed(white_var) + m.randomize() #Set constraints for constrain_param, constraint in constraints: constraint(constrain_param, m) - print(m) - m.randomize() - m.randomize() - #Set params for param_num in range(len(param_names)): name = param_names[param_num] m[name] = param_vals[param_num] - #m.optimize(max_iters=8) - print(m) - #if not m.checkgrad(step=step): - #m.checkgrad(verbose=1, step=step) - #NOTE this test appears to be stochastic for some likelihoods (student t?) - # appears to all be working in test mode right now... - #if isinstance(model, GPy.likelihoods.StudentT): - assert m.checkgrad(verbose=1, step=step) + try: + assert m.checkgrad(verbose=0, step=step) + except: + assert m.checkgrad(verbose=1, step=step) ########### # EP test # diff --git a/GPy/testing/model_tests.py b/GPy/testing/model_tests.py index d7339dd0..a2ba1575 100644 --- a/GPy/testing/model_tests.py +++ b/GPy/testing/model_tests.py @@ -48,7 +48,7 @@ class MiscTests(unittest.TestCase): Y = self.Y mu, std = Y.mean(0), Y.std(0) m = GPy.models.GPRegression(self.X, Y, kernel=k, normalizer=True) - m.optimize() + m.optimize(messages=True) assert(m.checkgrad()) k = GPy.kern.RBF(1) m2 = GPy.models.GPRegression(self.X, (Y-mu)/std, kernel=k, normalizer=False) diff --git a/GPy/testing/pickle_tests.py b/GPy/testing/pickle_tests.py index 64357b39..bf00055f 100644 --- a/GPy/testing/pickle_tests.py +++ b/GPy/testing/pickle_tests.py @@ -13,14 +13,15 @@ import tempfile from GPy.core.parameterization.param import Param from GPy.core.parameterization.observable_array import ObsAr from GPy.core.parameterization.priors import Gaussian -from GPy.kern._src.rbf import RBF -from GPy.kern._src.linear import Linear -from GPy.kern._src.static import Bias, White +from GPy.kern.src.rbf import RBF +from GPy.kern.src.linear import Linear +from GPy.kern.src.static import Bias, White from GPy.examples.dimensionality_reduction import mrd_simulation from GPy.core.parameterization.variational import NormalPosterior from GPy.models.gp_regression import GPRegression from functools import reduce from GPy.util.caching import Cacher +import GPy from pickle import PicklingError def toy_model(): @@ -60,13 +61,15 @@ class Test(ListDictTestCase): pio2 = pickle.load(f) self.assertListDictEquals(pio._properties, pio2._properties) - with tempfile.TemporaryFile('w+b') as f: - pickle.dump(piov, f) - f.seek(0) - pio2 = pickle.load(f) - #py3 fix - #self.assertListDictEquals(dict(piov.items()), dict(pio2.iteritems())) - self.assertListDictEquals(dict(piov.items()), dict(pio2.items())) + f = tempfile.TemporaryFile('w+b') + pickle.dump(piov, f) + f.seek(0) + pio2 = GPy.load(f) + f.close() + + #py3 fix + #self.assertListDictEquals(dict(piov.items()), dict(pio2.iteritems())) + self.assertListDictEquals(dict(piov.items()), dict(pio2.items())) def test_param(self): param = Param('test', np.arange(4*2).reshape(4,2)) diff --git a/GPy/testing/plotting_tests.py b/GPy/testing/plotting_tests.py new file mode 100644 index 00000000..a680fa6d --- /dev/null +++ b/GPy/testing/plotting_tests.py @@ -0,0 +1,351 @@ +#=============================================================================== +# Copyright (c) 2015, Max Zwiessele +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of GPy nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#=============================================================================== +import numpy as np +import GPy, os +from nose import SkipTest + +from ..util.config import config +from ..plotting import change_plotting_library +import unittest + +change_plotting_library('matplotlib') +if config.get('plotting', 'library') != 'matplotlib': + raise SkipTest("Matplotlib not installed, not testing plots") + + +try: + from matplotlib import cbook, pyplot as plt + from matplotlib.testing.compare import compare_images + from matplotlib.testing.noseclasses import ImageComparisonFailure +except ImportError: + raise SkipTest("Matplotlib not installed, not testing plots") + +extensions = ['png'] + +def _image_directories(): + """ + Compute the baseline and result image directories for testing *func*. + Create the result directory if it doesn't exist. + """ + basedir = os.path.splitext(os.path.relpath(os.path.abspath(__file__)))[0] + #module_name = __init__.__module__ + #mods = module_name.split('.') + #basedir = os.path.join(*mods) + result_dir = os.path.join(basedir, 'testresult') + baseline_dir = os.path.join(basedir, 'baseline') + if not os.path.exists(result_dir): + cbook.mkdirs(result_dir) + return baseline_dir, result_dir + + +def _sequenceEqual(a, b): + assert len(a) == len(b), "Sequences not same length" + for i, [x, y], in enumerate(zip(a, b)): + assert x == y, "element not matching {}".format(i) + +def _notFound(path): + raise IOError('File {} not in baseline') + +def _image_comparison(baseline_images, extensions=['pdf','svg','ong'], tol=11): + baseline_dir, result_dir = _image_directories() + for num, base in zip(plt.get_fignums(), baseline_images): + for ext in extensions: + fig = plt.figure(num) + fig.axes[0].set_axis_off() + fig.set_frameon(False) + fig.canvas.draw() + fig.savefig(os.path.join(result_dir, "{}.{}".format(base, ext)), transparent=True, edgecolor='none', facecolor='none') + for num, base in zip(plt.get_fignums(), baseline_images): + for ext in extensions: + #plt.close(num) + actual = os.path.join(result_dir, "{}.{}".format(base, ext)) + expected = os.path.join(baseline_dir, "{}.{}".format(base, ext)) + def do_test(): + err = compare_images(expected, actual, tol, in_decorator=True) + if err: + raise ImageComparisonFailure("Error between {} and {} is {:.5f}, which is bigger then the tolerance of {:.5f}".format(actual, expected, err['rms'], tol)) + yield do_test + plt.close('all') + +def test_figure(): + np.random.seed(1239847) + from GPy.plotting import plotting_library as pl + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + + ax, _ = pl().new_canvas(num=1) + def test_func(x): + return x[:, 0].reshape(3,3) + pl().imshow_interact(ax, test_func, extent=(-1,1,-1,1), resolution=3) + + ax, _ = pl().new_canvas() + def test_func_2(x): + y = x[:, 0].reshape(3,3) + anno = np.argmax(x, axis=1).reshape(3,3) + return y, anno + pl().annotation_heatmap_interact(ax, test_func_2, extent=(-1,1,-1,1), resolution=3) + pl().annotation_heatmap_interact(ax, test_func_2, extent=(-1,1,-1,1), resolution=3, imshow_kwargs=dict(interpolation='nearest')) + + ax, _ = pl().new_canvas(figsize=(4,3)) + x = np.linspace(0,1,100) + y = [0,1,2] + array = np.array([.4,.5]) + cmap = matplotlib.colors.LinearSegmentedColormap.from_list('WhToColor', ('r', 'b'), N=array.size) + pl().fill_gradient(ax, x, y, facecolors=['r', 'g'], array=array, cmap=cmap) + try: + pl().show_canvas(ax, tight_layout=True) + except: + # macosx tight layout not stable + pl().show_canvas(ax, tight_layout=False) + + ax, _ = pl().new_canvas(num=4, figsize=(4,3), projection='3d', xlabel='x', ylabel='y', zlabel='z', title='awsome title', xlim=(-1,1), ylim=(-1,1), zlim=(-3,3)) + z = 2-np.abs(np.linspace(-2,2,(100)))+1 + x, y = z*np.sin(np.linspace(-2*np.pi,2*np.pi,(100))), z*np.cos(np.linspace(-np.pi,np.pi,(100))) + pl().plot(ax, x, y, z, linewidth=2) + for do_test in _image_comparison( + baseline_images=['coverage_{}'.format(sub) for sub in ["imshow_interact",'annotation_interact','gradient','3d_plot',]], + extensions=extensions): + yield (do_test, ) + + +def test_kernel(): + np.random.seed(1239847) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + k = GPy.kern.RBF(5, ARD=True) * GPy.kern.Linear(3, active_dims=[0,2,4], ARD=True) + GPy.kern.Bias(2) + k.randomize() + k2 = GPy.kern.RBF(5, ARD=True) * GPy.kern.Linear(3, active_dims=[0,2,4], ARD=True) + GPy.kern.Bias(2) + GPy.kern.White(4) + k2[:-1] = k[:] + k2.plot_ARD(['rbf', 'linear', 'bias'], legend=True) + k2.plot_covariance(visible_dims=[0, 3], plot_limits=(-1,3)) + k2.plot_covariance(visible_dims=[2], plot_limits=(-1, 3)) + k2.plot_covariance(visible_dims=[2, 4], plot_limits=((-1, 0), (5, 3)), projection='3d') + k2.plot_covariance(visible_dims=[1, 4]) + for do_test in _image_comparison( + baseline_images=['kern_{}'.format(sub) for sub in ["ARD", 'cov_2d', 'cov_1d', 'cov_3d', 'cov_no_lim']], + extensions=extensions): + yield (do_test, ) + +def test_plot(): + np.random.seed(111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + X = np.random.uniform(-2, 2, (40, 1)) + f = .2 * np.sin(1.3*X) + 1.3*np.cos(2*X) + Y = f+np.random.normal(0, .1, f.shape) + m = GPy.models.SparseGPRegression(X, Y, X_variance=np.ones_like(X)*[0.06]) + #m.optimize() + m.plot_data() + m.plot_mean() + m.plot_confidence() + m.plot_density() + m.plot_errorbars_trainset() + m.plot_samples() + m.plot_data_error() + for do_test in _image_comparison(baseline_images=['gp_{}'.format(sub) for sub in ["data", "mean", 'conf', + 'density', + 'out_error', + 'samples', 'in_error']], extensions=extensions): + yield (do_test, ) + +def test_twod(): + np.random.seed(11111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + X = np.random.uniform(-2, 2, (40, 2)) + f = .2 * np.sin(1.3*X[:,[0]]) + 1.3*np.cos(2*X[:,[1]]) + Y = f+np.random.normal(0, .1, f.shape) + m = GPy.models.SparseGPRegression(X, Y, X_variance=np.ones_like(X)*[0.01, 0.2]) + #m.optimize() + m.plot_data() + m.plot_mean() + m.plot_inducing() + #m.plot_errorbars_trainset() + m.plot_data_error() + for do_test in _image_comparison(baseline_images=['gp_2d_{}'.format(sub) for sub in ["data", "mean", + 'inducing', + #'out_error', + 'in_error', + ]], extensions=extensions): + yield (do_test, ) + +def test_threed(): + np.random.seed(11111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + X = np.random.uniform(-2, 2, (40, 2)) + f = .2 * np.sin(1.3*X[:,[0]]) + 1.3*np.cos(2*X[:,[1]]) + Y = f+np.random.normal(0, .1, f.shape) + m = GPy.models.SparseGPRegression(X, Y) + m.likelihood.variance = .1 + #m.optimize() + m.plot_samples(projection='3d', samples=1) + m.plot_samples(projection='3d', plot_raw=False, samples=1) + plt.close('all') + m.plot_data(projection='3d') + m.plot_mean(projection='3d') + m.plot_inducing(projection='3d') + #m.plot_errorbars_trainset(projection='3d') + for do_test in _image_comparison(baseline_images=['gp_3d_{}'.format(sub) for sub in ["data", "mean", 'inducing', + #'error', + #"samples", "samples_lik" + ]], extensions=extensions): + yield (do_test, ) + +def test_sparse(): + np.random.seed(11111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + X = np.random.uniform(-2, 2, (40, 1)) + f = .2 * np.sin(1.3*X) + 1.3*np.cos(2*X) + Y = f+np.random.normal(0, .1, f.shape) + m = GPy.models.SparseGPRegression(X, Y, X_variance=np.ones_like(X)*0.1) + #m.optimize() + #m.plot_inducing() + m.plot_data() + for do_test in _image_comparison(baseline_images=['sparse_gp_{}'.format(sub) for sub in ['data_error']], extensions=extensions): + yield (do_test, ) + +def test_classification(): + np.random.seed(11111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + X = np.random.uniform(-2, 2, (40, 1)) + f = .2 * np.sin(1.3*X) + 1.3*np.cos(2*X) + Y = f+np.random.normal(0, .1, f.shape) + m = GPy.models.GPClassification(X, Y>Y.mean()) + #m.optimize() + _, ax = plt.subplots() + m.plot(plot_raw=False, apply_link=False, ax=ax) + m.plot_errorbars_trainset(plot_raw=False, apply_link=False, ax=ax) + _, ax = plt.subplots() + m.plot(plot_raw=True, apply_link=False, ax=ax) + m.plot_errorbars_trainset(plot_raw=True, apply_link=False, ax=ax) + _, ax = plt.subplots() + m.plot(plot_raw=True, apply_link=True, ax=ax) + m.plot_errorbars_trainset(plot_raw=True, apply_link=True, ax=ax) + for do_test in _image_comparison(baseline_images=['gp_class_{}'.format(sub) for sub in ["likelihood", "raw", 'raw_link']], extensions=extensions): + yield (do_test, ) + + +def test_sparse_classification(): + np.random.seed(11111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + X = np.random.uniform(-2, 2, (40, 1)) + f = .2 * np.sin(1.3*X) + 1.3*np.cos(2*X) + Y = f+np.random.normal(0, .1, f.shape) + m = GPy.models.SparseGPClassification(X, Y>Y.mean()) + #m.optimize() + m.plot(plot_raw=False, apply_link=False, samples_likelihood=3) + np.random.seed(111) + m.plot(plot_raw=True, apply_link=False, samples=3) + np.random.seed(111) + m.plot(plot_raw=True, apply_link=True, samples=3) + for do_test in _image_comparison(baseline_images=['sparse_gp_class_{}'.format(sub) for sub in ["likelihood", "raw", 'raw_link']], extensions=extensions): + yield (do_test, ) + +def test_gplvm(): + from ..examples.dimensionality_reduction import _simulate_matern + from ..kern import RBF + from ..models import GPLVM + np.random.seed(11111) + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + Q = 3 + _, _, Ylist = _simulate_matern(5, 1, 1, 100, num_inducing=5, plot_sim=False) + Y = Ylist[0] + k = RBF(Q, ARD=True) # + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) + m = GPLVM(Y, Q, init="PCA", kernel=k) + m.likelihood.variance = .1 + #m.optimize(messages=0) + labels = np.random.multinomial(1, np.random.dirichlet([.3333333, .3333333, .3333333]), size=(m.Y.shape[0])).nonzero()[1] + np.random.seed(111) + m.plot_latent() + np.random.seed(111) + m.plot_scatter(projection='3d', labels=labels) + np.random.seed(111) + m.plot_magnification(labels=labels) + m.plot_steepest_gradient_map(resolution=7) + for do_test in _image_comparison(baseline_images=['gplvm_{}'.format(sub) for sub in ["latent", "latent_3d", "magnification", 'gradient']], extensions=extensions): + yield (do_test, ) + +def test_bayesian_gplvm(): + from ..examples.dimensionality_reduction import _simulate_matern + from ..kern import RBF + from ..models import BayesianGPLVM + import matplotlib + matplotlib.rcParams.update(matplotlib.rcParamsDefault) + matplotlib.rcParams[u'figure.figsize'] = (4,3) + matplotlib.rcParams[u'text.usetex'] = False + np.random.seed(111) + Q = 3 + _, _, Ylist = _simulate_matern(5, 1, 1, 100, num_inducing=5, plot_sim=False) + Y = Ylist[0] + k = RBF(Q, ARD=True) # + kern.white(Q, _np.exp(-2)) # + kern.bias(Q) + # k = kern.RBF(Q, ARD=True, lengthscale=10.) + m = BayesianGPLVM(Y, Q, init="PCA", kernel=k) + m.likelihood.variance = .1 + #m.optimize(messages=0) + labels = np.random.multinomial(1, np.random.dirichlet([.3333333, .3333333, .3333333]), size=(m.Y.shape[0])).nonzero()[1] + np.random.seed(111) + m.plot_inducing(projection='2d') + np.random.seed(111) + m.plot_inducing(projection='3d') + np.random.seed(111) + m.plot_scatter(projection='3d') + np.random.seed(111) + m.plot_magnification(labels=labels) + np.random.seed(111) + m.plot_steepest_gradient_map(resolution=7) + for do_test in _image_comparison(baseline_images=['bayesian_gplvm_{}'.format(sub) for sub in ["inducing", "inducing_3d", "latent_3d", "magnification", 'gradient']], extensions=extensions): + yield (do_test, ) + +if __name__ == '__main__': + import nose + nose.main() diff --git a/GPy/testing/plotting_tests/baseline/bayesian_gplvm_gradient.png b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_gradient.png new file mode 100644 index 00000000..ccc72002 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_gradient.png differ diff --git a/GPy/testing/plotting_tests/baseline/bayesian_gplvm_inducing.png b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_inducing.png new file mode 100644 index 00000000..9ef57a9a Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_inducing.png differ diff --git a/GPy/testing/plotting_tests/baseline/bayesian_gplvm_inducing_3d.png b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_inducing_3d.png new file mode 100644 index 00000000..6f46d423 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_inducing_3d.png differ diff --git a/GPy/testing/plotting_tests/baseline/bayesian_gplvm_latent_3d.png b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_latent_3d.png new file mode 100644 index 00000000..db81f483 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_latent_3d.png differ diff --git a/GPy/testing/plotting_tests/baseline/bayesian_gplvm_magnification.png b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_magnification.png new file mode 100644 index 00000000..ebb624a6 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/bayesian_gplvm_magnification.png differ diff --git a/GPy/testing/plotting_tests/baseline/coverage_3d_plot.png b/GPy/testing/plotting_tests/baseline/coverage_3d_plot.png new file mode 100644 index 00000000..c5469dd0 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/coverage_3d_plot.png differ diff --git a/GPy/testing/plotting_tests/baseline/coverage_annotation_interact.png b/GPy/testing/plotting_tests/baseline/coverage_annotation_interact.png new file mode 100644 index 00000000..7555a872 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/coverage_annotation_interact.png differ diff --git a/GPy/testing/plotting_tests/baseline/coverage_gradient.png b/GPy/testing/plotting_tests/baseline/coverage_gradient.png new file mode 100644 index 00000000..de5fb4f3 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/coverage_gradient.png differ diff --git a/GPy/testing/plotting_tests/baseline/coverage_imshow_interact.png b/GPy/testing/plotting_tests/baseline/coverage_imshow_interact.png new file mode 100644 index 00000000..70c59276 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/coverage_imshow_interact.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_2d_data.png b/GPy/testing/plotting_tests/baseline/gp_2d_data.png new file mode 100644 index 00000000..e16283d4 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_2d_data.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_2d_in_error.png b/GPy/testing/plotting_tests/baseline/gp_2d_in_error.png new file mode 100644 index 00000000..9f0652c2 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_2d_in_error.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_2d_inducing.png b/GPy/testing/plotting_tests/baseline/gp_2d_inducing.png new file mode 100644 index 00000000..3f3c153d Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_2d_inducing.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_2d_mean.png b/GPy/testing/plotting_tests/baseline/gp_2d_mean.png new file mode 100644 index 00000000..9f376fe6 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_2d_mean.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_3d_data.png b/GPy/testing/plotting_tests/baseline/gp_3d_data.png new file mode 100644 index 00000000..1fa42efb Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_3d_data.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_3d_inducing.png b/GPy/testing/plotting_tests/baseline/gp_3d_inducing.png new file mode 100644 index 00000000..00feec6e Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_3d_inducing.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_3d_mean.png b/GPy/testing/plotting_tests/baseline/gp_3d_mean.png new file mode 100644 index 00000000..87a2c282 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_3d_mean.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_class_likelihood.png b/GPy/testing/plotting_tests/baseline/gp_class_likelihood.png new file mode 100644 index 00000000..9faaeee7 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_class_likelihood.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_class_raw.png b/GPy/testing/plotting_tests/baseline/gp_class_raw.png new file mode 100644 index 00000000..a0e04b66 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_class_raw.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_class_raw_link.png b/GPy/testing/plotting_tests/baseline/gp_class_raw_link.png new file mode 100644 index 00000000..41d23556 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_class_raw_link.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_conf.png b/GPy/testing/plotting_tests/baseline/gp_conf.png new file mode 100644 index 00000000..4dcd5919 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_conf.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_data.png b/GPy/testing/plotting_tests/baseline/gp_data.png new file mode 100644 index 00000000..08c3845c Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_data.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_density.png b/GPy/testing/plotting_tests/baseline/gp_density.png new file mode 100644 index 00000000..953d571b Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_density.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_error.png b/GPy/testing/plotting_tests/baseline/gp_error.png new file mode 100644 index 00000000..38c65afc Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_error.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_in_error.png b/GPy/testing/plotting_tests/baseline/gp_in_error.png new file mode 100644 index 00000000..54d45479 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_in_error.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_mean.png b/GPy/testing/plotting_tests/baseline/gp_mean.png new file mode 100644 index 00000000..735e3cc6 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_mean.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_out_error.png b/GPy/testing/plotting_tests/baseline/gp_out_error.png new file mode 100644 index 00000000..2d7c1968 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_out_error.png differ diff --git a/GPy/testing/plotting_tests/baseline/gp_samples.png b/GPy/testing/plotting_tests/baseline/gp_samples.png new file mode 100644 index 00000000..e9641a23 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gp_samples.png differ diff --git a/GPy/testing/plotting_tests/baseline/gplvm_gradient.png b/GPy/testing/plotting_tests/baseline/gplvm_gradient.png new file mode 100644 index 00000000..2dd49320 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gplvm_gradient.png differ diff --git a/GPy/testing/plotting_tests/baseline/gplvm_latent.png b/GPy/testing/plotting_tests/baseline/gplvm_latent.png new file mode 100644 index 00000000..eb58a709 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gplvm_latent.png differ diff --git a/GPy/testing/plotting_tests/baseline/gplvm_latent_3d.png b/GPy/testing/plotting_tests/baseline/gplvm_latent_3d.png new file mode 100644 index 00000000..da040371 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gplvm_latent_3d.png differ diff --git a/GPy/testing/plotting_tests/baseline/gplvm_magnification.png b/GPy/testing/plotting_tests/baseline/gplvm_magnification.png new file mode 100644 index 00000000..2f09cf3c Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/gplvm_magnification.png differ diff --git a/GPy/testing/plotting_tests/baseline/kern_ARD.png b/GPy/testing/plotting_tests/baseline/kern_ARD.png new file mode 100644 index 00000000..7b917abd Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/kern_ARD.png differ diff --git a/GPy/testing/plotting_tests/baseline/kern_cov_1d.png b/GPy/testing/plotting_tests/baseline/kern_cov_1d.png new file mode 100644 index 00000000..449a686d Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/kern_cov_1d.png differ diff --git a/GPy/testing/plotting_tests/baseline/kern_cov_2d.png b/GPy/testing/plotting_tests/baseline/kern_cov_2d.png new file mode 100644 index 00000000..db76f5b6 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/kern_cov_2d.png differ diff --git a/GPy/testing/plotting_tests/baseline/kern_cov_3d.png b/GPy/testing/plotting_tests/baseline/kern_cov_3d.png new file mode 100644 index 00000000..31b32b5e Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/kern_cov_3d.png differ diff --git a/GPy/testing/plotting_tests/baseline/kern_cov_no_lim.png b/GPy/testing/plotting_tests/baseline/kern_cov_no_lim.png new file mode 100644 index 00000000..ed9960f9 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/kern_cov_no_lim.png differ diff --git a/GPy/testing/plotting_tests/baseline/sparse_gp_class_likelihood.png b/GPy/testing/plotting_tests/baseline/sparse_gp_class_likelihood.png new file mode 100644 index 00000000..a29e8eba Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/sparse_gp_class_likelihood.png differ diff --git a/GPy/testing/plotting_tests/baseline/sparse_gp_class_raw.png b/GPy/testing/plotting_tests/baseline/sparse_gp_class_raw.png new file mode 100644 index 00000000..9fc027f0 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/sparse_gp_class_raw.png differ diff --git a/GPy/testing/plotting_tests/baseline/sparse_gp_class_raw_link.png b/GPy/testing/plotting_tests/baseline/sparse_gp_class_raw_link.png new file mode 100644 index 00000000..c24d2d66 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/sparse_gp_class_raw_link.png differ diff --git a/GPy/testing/plotting_tests/baseline/sparse_gp_data_error.png b/GPy/testing/plotting_tests/baseline/sparse_gp_data_error.png new file mode 100644 index 00000000..c78a8df1 Binary files /dev/null and b/GPy/testing/plotting_tests/baseline/sparse_gp_data_error.png differ diff --git a/GPy/util/config.py b/GPy/util/config.py index 312d6991..c2b581f7 100644 --- a/GPy/util/config.py +++ b/GPy/util/config.py @@ -12,8 +12,6 @@ except ImportError: config = configparser.ConfigParser() - - # This is the default configuration file that always needs to be present. default_file = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'defaults.cfg')) @@ -23,10 +21,11 @@ local_file = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'in # This specifies configurations specific to the user (it is found in the user home directory) home = os.getenv('HOME') or os.getenv('USERPROFILE') -user_file = os.path.join(home,'.gpy_user.cfg') +user_file = os.path.join(home,'.config','gpy', 'user.cfg') # Read in the given files. config.readfp(open(default_file)) config.read([local_file, user_file]) + if not config: raise ValueError("No configuration file found at either " + user_file + " or " + local_file + " or " + default_file + ".") diff --git a/GPy/util/datasets.py b/GPy/util/datasets.py index f9173365..b722ba45 100644 --- a/GPy/util/datasets.py +++ b/GPy/util/datasets.py @@ -94,10 +94,13 @@ def prompt_user(prompt): def data_available(dataset_name=None): """Check if the data set is available on the local machine already.""" - from itertools import izip_longest + try: + from itertools import izip_longest + except ImportError: + from itertools import zip_longest as izip_longest dr = data_resources[dataset_name] zip_urls = (dr['files'], ) - if dr.has_key('save_names'): zip_urls += (dr['save_names'], ) + if 'save_names' in dr: zip_urls += (dr['save_names'], ) else: zip_urls += ([],) for file_list, save_list in izip_longest(*zip_urls, fillvalue=[]): diff --git a/GPy/util/pca.py b/GPy/util/pca.py index 7168a28f..edb8bb7d 100644 --- a/GPy/util/pca.py +++ b/GPy/util/pca.py @@ -81,7 +81,7 @@ class PCA(object): """ Plot fractions of Eigenvalues sorted in descending order. """ - from GPy.plotting.matplot_dep import Tango + from ..plotting import Tango Tango.reset() col = Tango.nextMedium() if ax is None: diff --git a/README.md b/README.md index 87580b4f..caeea5e7 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,32 @@ # GPy -A Gaussian processes framework in Python. +The Gaussian processes framework in Python. * [GPy homepage](http://sheffieldml.github.io/GPy/) * [Tutorial notebooks](http://nbviewer.ipython.org/github/SheffieldML/notebook/blob/master/GPy/index.ipynb) * [User mailing list](https://lists.shef.ac.uk/sympa/subscribe/gpy-users) -* [Online documentation](https://gpy.readthedocs.org/en/latest/) +* [Developer documentation](http://pythonhosted.org/GPy/) * [Unit tests (Travis-CI)](https://travis-ci.org/SheffieldML/GPy) * [![licence](https://img.shields.io/badge/licence-BSD-blue.svg)](http://opensource.org/licenses/BSD-3-Clause) -#### Continuous integration -| | Travis-CI | Codecov | Readthedocs | +## Continuous integration + +| | Travis-CI | Codecov | RTFD | | ---: | :--: | :---: | :---: | -| **master:** | [![master](https://travis-ci.org/SheffieldML/GPy.svg?branch=master)](https://travis-ci.org/SheffieldML/GPy) | [![codecov.io](http://codecov.io/github/SheffieldML/GPy/coverage.svg?branch=master)](http://codecov.io/github/SheffieldML/GPy?branch=master) | [![mdocs](https://img.shields.io/badge/docs-master-blue.svg?style=flat)](http://gpy.readthedocs.org/en/master/) | -| **devel:** | [![devel](https://travis-ci.org/SheffieldML/GPy.svg?branch=devel)](https://travis-ci.org/SheffieldML/GPy) | [![codecov.io](http://codecov.io/github/SheffieldML/GPy/coverage.svg?branch=devel)](http://codecov.io/github/SheffieldML/GPy?branch=devel) | [![ddocs](https://img.shields.io/badge/docs-devel-blue.svg?style=flat)](http://gpy.readthedocs.org/en/devel/) | +| **master:** | [![master](https://travis-ci.org/SheffieldML/GPy.svg?branch=master)](https://travis-ci.org/SheffieldML/GPy) | [![codecov.io master](http://codecov.io/github/SheffieldML/GPy/coverage.svg?branch=master)](http://codecov.io/github/SheffieldML/GPy?branch=master) | [![Documentation Status](https://readthedocs.org/projects/gpy/badge/?version=master)](http://gpy.readthedocs.org/en/master/?badge=master) | +| **devel:** | [![devel](https://travis-ci.org/SheffieldML/GPy.svg?branch=devel)](https://travis-ci.org/SheffieldML/GPy) | [![codecov.io devel](http://codecov.io/github/SheffieldML/GPy/coverage.svg?branch=devel)](http://codecov.io/github/SheffieldML/GPy?branch=devel) | [![Documentation Status](https://readthedocs.org/projects/gpy/badge/?version=devel)](http://gpy.readthedocs.org/en/devel/?badge=devel) | -### Supported Platforms: +## Supported Platforms: -[](https://www.python.org/) [](http://www.microsoft.com/en-gb/windows) [](http://www.apple.com/osx/) [](https://en.wikipedia.org/wiki/List_of_Linux_distributions) ----- +[](https://www.python.org/) +[](http://www.microsoft.com/en-gb/windows) +[](http://www.apple.com/osx/) +[](https://en.wikipedia.org/wiki/List_of_Linux_distributions) Python 2.7, 3.3 and higher -### Citation +## Citation @Misc{gpy2014, author = {{The GPy authors}}, @@ -32,11 +35,11 @@ Python 2.7, 3.3 and higher year = {2012--2015} } -### Pronounciation: dʒí páj +### Pronounciation: We like to pronounce it 'g-pie'. -### Getting started: installing with pip +## Getting started: installing with pip We are now requiring the newest version (0.16) of [scipy](http://www.scipy.org/) and thus, we strongly recommend using @@ -45,29 +48,49 @@ With anaconda you can install GPy by the following: conda update scipy pip install gpy - -We've also had luck with [enthought](http://www.enthought.com), -although enthought currently (as of 8th Sep. 2015) does not support scipy 0.16. -If you'd like to install from source, or want to contribute to the project (e.g. by sending pull requests via github), read on. +We've also had luck with [enthought](http://www.enthought.com). Install scipy 0.16 (or later) + and then pip install GPy: + + pip install gpy + +If you'd like to install from source, or want to contribute to the project (i.e. by sending pull requests via github), read on. ### Troubleshooting installation problems If you're having trouble installing GPy via `pip install GPy` here is a probable solution: - git clone https://github.com/mikecroucher/GPy.git + git clone https://github.com/SheffieldML/GPy.git cd GPy git checkout devel - python3 setup.py build_ext --inplace - nosetests3 GPy/testing + python setup.py build_ext --inplace + nosetests GPy/testing ### Direct downloads -[![PyPI version](https://badge.fury.io/py/GPy.svg)](https://pypi.python.org/pypi/GPy) [![source](https://img.shields.io/badge/download-source-green.svg)](https://github.com/SheffieldML/GPy/releases/latest) -[![Windows](https://img.shields.io/badge/download-windows-orange.svg)](https://github.com/SheffieldML/GPy/releases/latest) -[![MacOSX](https://img.shields.io/badge/download-macosx-blue.svg)](https://github.com/SheffieldML/GPy/releases/latest) +[![PyPI version](https://badge.fury.io/py/GPy.svg)](https://pypi.python.org/pypi/GPy) [![source](https://img.shields.io/badge/download-source-green.svg)](https://pypi.python.org/pypi/GPy) +[![Windows](https://img.shields.io/badge/download-windows-orange.svg)](https://pypi.python.org/pypi/GPy) +[![MacOSX](https://img.shields.io/badge/download-macosx-blue.svg)](https://pypi.python.org/pypi/GPy) -### Ubuntu hackers +## Running unit tests: + +Ensure nose is installed via pip: + + pip install nose + +Run nosetests from the root directory of the repository: + + nosetests -v GPy/testing + +or from within IPython + + import GPy; GPy.tests() + +or using setuptools + + python setup.py test + +## Ubuntu hackers > Note: Right now the Ubuntu package index does not include scipy 0.16.0, and thus, cannot > be used for GPy. We hope this gets fixed soon. @@ -82,88 +105,31 @@ clone this git repository and add it to your path: echo 'PYTHONPATH=$PYTHONPATH:~/SheffieldML' >> ~/.bashrc - -### OSX - - -We were working hard to make pre-built distributions ready. -You can now install GPy via pip on MacOSX using -[anaconda python distribution](http://continuum.io/downloads): - - conda update scipy - pip install gpy - -If this does not work, then you need to build GPy yourself, -using the [development toolkits](https://developer.apple.com/xcode/). -Download/clone GPy and run the build process: - - conda update scipy - git clone git@github.com:SheffieldML/GPy.git ~/GPy - cd ~/GPy - python setup.py install - -If you do not wish to build the C extensions (10 times speedup), -you can run the pure python installations, by just adding GPy -to your python path. - - echo 'PYTHONPATH=$PYTHONPATH:~/SheffieldML' >> ~/.profile - - - -### Compiling documentation: - +## Compiling documentation: The documentation is stored in doc/ and is compiled with the Sphinx Python documentation generator, and is written in the reStructuredText format. The Sphinx documentation is available here: http://sphinx-doc.org/latest/contents.html - -##### Installing dependencies: - +**Installing dependencies:** To compile the documentation, first ensure that Sphinx is installed. On Debian-based systems, this can be achieved as follows: sudo apt-get install python-pip sudo pip install sphinx -A LaTeX distribution is also required to compile the equations. Note that the extra packages are necessary to install the unicode packages. To compile the equations to PNG format for use in HTML pages, the package *dvipng* must be installed. IPython is also required. On Debian-based systems, this can be achieved as follows: - - sudo apt-get install texlive texlive-latex-extra texlive-base texlive-recommended - sudo apt-get install dvipng - sudo apt-get install ipython - - -#### Compiling documentation: - +**Compiling documentation:** The documentation can be compiled as follows: cd doc + sphinx-apidoc -o source/ ../GPy/ make html -The HTML files are then stored in doc/_build/ - - -## Running unit tests: - - -Ensure nose is installed via pip: - - pip install nose - -Run nosetests from the root directory of the repository: - - nosetests -v GPy/testing - -or from within IPython - - import GPy; GPy.tests() - - +The HTML files are then stored in doc/build/html ## Funding Acknowledgements - Current support for the GPy software is coming through the following projects. * [EU FP7-HEALTH Project Ref 305626](http://radiant-project.eu) "RADIANT: Rapid Development and Distribution of Statistical Tools for High-Throughput Sequencing Data" @@ -175,7 +141,8 @@ Current support for the GPy software is coming through the following projects. * [EU FP7-ICT Project Ref 612139](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/wysiwyd/) "WYSIWYD: What You Say is What You Did" Previous support for the GPy software came from the following projects: -* [BBSRC Project No BB/K011197/1](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/recombinant/) "Linking recombinant gene sequence to protein product manufacturability using CHO cell genomic resources" -* [EU FP7-KBBE Project Ref 289434](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/biopredyn/) "From Data to Models: New Bioinformatics Methods and Tools for Data-Driven Predictive Dynamic Modelling in Biotechnological Applications" -* [BBSRC Project No BB/H018123/2](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/iterative/) "An iterative pipeline of computational modelling and experimental design for uncovering gene regulatory networks in vertebrates" -* [Erasysbio](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/synergy/) "SYNERGY: Systems approach to gene regulation biology through nuclear receptors" + +- [BBSRC Project No BB/K011197/1](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/recombinant/) "Linking recombinant gene sequence to protein product manufacturability using CHO cell genomic resources" +- [EU FP7-KBBE Project Ref 289434](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/biopredyn/) "From Data to Models: New Bioinformatics Methods and Tools for Data-Driven Predictive Dynamic Modelling in Biotechnological Applications" +- [BBSRC Project No BB/H018123/2](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/iterative/) "An iterative pipeline of computational modelling and experimental design for uncovering gene regulatory networks in vertebrates" +- [Erasysbio](http://staffwww.dcs.shef.ac.uk/people/N.Lawrence/projects/synergy/) "SYNERGY: Systems approach to gene regulation biology through nuclear receptors" diff --git a/doc/source/.#conf.py b/doc/source/.#conf.py deleted file mode 120000 index 307d8733..00000000 --- a/doc/source/.#conf.py +++ /dev/null @@ -1 +0,0 @@ -maxz@maxz-sitran.8058:1442579222 \ No newline at end of file diff --git a/doc/source/GPy.kern.rst b/doc/source/GPy.kern.rst index 9ee59ed6..bb61443b 100644 --- a/doc/source/GPy.kern.rst +++ b/doc/source/GPy.kern.rst @@ -1,6 +1,13 @@ GPy.kern package ================ +Subpackages +----------- + +.. toctree:: + + GPy.kern.src + Module contents --------------- diff --git a/doc/source/GPy.kern.src.psi_comp.rst b/doc/source/GPy.kern.src.psi_comp.rst new file mode 100644 index 00000000..dfa3c270 --- /dev/null +++ b/doc/source/GPy.kern.src.psi_comp.rst @@ -0,0 +1,70 @@ +GPy.kern.src.psi_comp package +============================= + +Submodules +---------- + +GPy.kern.src.psi_comp.gaussherm module +-------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.gaussherm + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.psi_comp.linear_psi_comp module +-------------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.linear_psi_comp + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.psi_comp.rbf_psi_comp module +----------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.rbf_psi_comp + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.psi_comp.rbf_psi_gpucomp module +-------------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.rbf_psi_gpucomp + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.psi_comp.sslinear_psi_comp module +---------------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.sslinear_psi_comp + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.psi_comp.ssrbf_psi_comp module +------------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.ssrbf_psi_comp + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.psi_comp.ssrbf_psi_gpucomp module +---------------------------------------------- + +.. automodule:: GPy.kern.src.psi_comp.ssrbf_psi_gpucomp + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: GPy.kern.src.psi_comp + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/GPy.kern.src.rst b/doc/source/GPy.kern.src.rst new file mode 100644 index 00000000..ccbc3f99 --- /dev/null +++ b/doc/source/GPy.kern.src.rst @@ -0,0 +1,237 @@ +GPy.kern.src package +==================== + +Subpackages +----------- + +.. toctree:: + + GPy.kern.src.psi_comp + +Submodules +---------- + +GPy.kern.src.ODE_UY module +-------------------------- + +.. automodule:: GPy.kern.src.ODE_UY + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.ODE_UYC module +--------------------------- + +.. automodule:: GPy.kern.src.ODE_UYC + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.ODE_st module +-------------------------- + +.. automodule:: GPy.kern.src.ODE_st + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.ODE_t module +------------------------- + +.. automodule:: GPy.kern.src.ODE_t + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.add module +----------------------- + +.. automodule:: GPy.kern.src.add + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.basis_funcs module +------------------------------- + +.. automodule:: GPy.kern.src.basis_funcs + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.brownian module +---------------------------- + +.. automodule:: GPy.kern.src.brownian + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.coregionalize module +--------------------------------- + +.. automodule:: GPy.kern.src.coregionalize + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.coregionalize_cython module +---------------------------------------- + +.. automodule:: GPy.kern.src.coregionalize_cython + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.eq_ode2 module +--------------------------- + +.. automodule:: GPy.kern.src.eq_ode2 + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.independent_outputs module +--------------------------------------- + +.. automodule:: GPy.kern.src.independent_outputs + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.kern module +------------------------ + +.. automodule:: GPy.kern.src.kern + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.kernel_slice_operations module +------------------------------------------- + +.. automodule:: GPy.kern.src.kernel_slice_operations + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.linear module +-------------------------- + +.. automodule:: GPy.kern.src.linear + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.mlp module +----------------------- + +.. automodule:: GPy.kern.src.mlp + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.periodic module +---------------------------- + +.. automodule:: GPy.kern.src.periodic + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.poly module +------------------------ + +.. automodule:: GPy.kern.src.poly + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.prod module +------------------------ + +.. automodule:: GPy.kern.src.prod + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.rbf module +----------------------- + +.. automodule:: GPy.kern.src.rbf + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.spline module +-------------------------- + +.. automodule:: GPy.kern.src.spline + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.splitKern module +----------------------------- + +.. automodule:: GPy.kern.src.splitKern + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.standard_periodic module +------------------------------------- + +.. automodule:: GPy.kern.src.standard_periodic + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.static module +-------------------------- + +.. automodule:: GPy.kern.src.static + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.stationary module +------------------------------ + +.. automodule:: GPy.kern.src.stationary + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.stationary_cython module +------------------------------------- + +.. automodule:: GPy.kern.src.stationary_cython + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.symbolic module +---------------------------- + +.. automodule:: GPy.kern.src.symbolic + :members: + :undoc-members: + :show-inheritance: + +GPy.kern.src.trunclinear module +------------------------------- + +.. automodule:: GPy.kern.src.trunclinear + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: GPy.kern.src + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/GPy.plotting.gpy_plot.rst b/doc/source/GPy.plotting.gpy_plot.rst new file mode 100644 index 00000000..8391cd3a --- /dev/null +++ b/doc/source/GPy.plotting.gpy_plot.rst @@ -0,0 +1,62 @@ +GPy.plotting.gpy_plot package +============================= + +Submodules +---------- + +GPy.plotting.gpy_plot.data_plots module +--------------------------------------- + +.. automodule:: GPy.plotting.gpy_plot.data_plots + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.gpy_plot.gp_plots module +------------------------------------- + +.. automodule:: GPy.plotting.gpy_plot.gp_plots + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.gpy_plot.inference_plots module +-------------------------------------------- + +.. automodule:: GPy.plotting.gpy_plot.inference_plots + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.gpy_plot.kernel_plots module +----------------------------------------- + +.. automodule:: GPy.plotting.gpy_plot.kernel_plots + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.gpy_plot.latent_plots module +----------------------------------------- + +.. automodule:: GPy.plotting.gpy_plot.latent_plots + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.gpy_plot.plot_util module +-------------------------------------- + +.. automodule:: GPy.plotting.gpy_plot.plot_util + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: GPy.plotting.gpy_plot + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/GPy.plotting.matplot_dep.controllers.rst b/doc/source/GPy.plotting.matplot_dep.controllers.rst new file mode 100644 index 00000000..239f8e79 --- /dev/null +++ b/doc/source/GPy.plotting.matplot_dep.controllers.rst @@ -0,0 +1,30 @@ +GPy.plotting.matplot_dep.controllers package +============================================ + +Submodules +---------- + +GPy.plotting.matplot_dep.controllers.axis_event_controller module +----------------------------------------------------------------- + +.. automodule:: GPy.plotting.matplot_dep.controllers.axis_event_controller + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.matplot_dep.controllers.imshow_controller module +------------------------------------------------------------- + +.. automodule:: GPy.plotting.matplot_dep.controllers.imshow_controller + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: GPy.plotting.matplot_dep.controllers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/GPy.plotting.matplot_dep.latent_space_visualizations.controllers.rst b/doc/source/GPy.plotting.matplot_dep.latent_space_visualizations.controllers.rst deleted file mode 100644 index 71826ed6..00000000 --- a/doc/source/GPy.plotting.matplot_dep.latent_space_visualizations.controllers.rst +++ /dev/null @@ -1,30 +0,0 @@ -GPy.plotting.matplot_dep.latent_space_visualizations.controllers package -======================================================================== - -Submodules ----------- - -GPy.plotting.matplot_dep.latent_space_visualizations.controllers.axis_event_controller module ---------------------------------------------------------------------------------------------- - -.. automodule:: GPy.plotting.matplot_dep.latent_space_visualizations.controllers.axis_event_controller - :members: - :undoc-members: - :show-inheritance: - -GPy.plotting.matplot_dep.latent_space_visualizations.controllers.imshow_controller module ------------------------------------------------------------------------------------------ - -.. automodule:: GPy.plotting.matplot_dep.latent_space_visualizations.controllers.imshow_controller - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: GPy.plotting.matplot_dep.latent_space_visualizations.controllers - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/GPy.plotting.matplot_dep.latent_space_visualizations.rst b/doc/source/GPy.plotting.matplot_dep.latent_space_visualizations.rst deleted file mode 100644 index 6e5cf4bd..00000000 --- a/doc/source/GPy.plotting.matplot_dep.latent_space_visualizations.rst +++ /dev/null @@ -1,17 +0,0 @@ -GPy.plotting.matplot_dep.latent_space_visualizations package -============================================================ - -Subpackages ------------ - -.. toctree:: - - GPy.plotting.matplot_dep.latent_space_visualizations.controllers - -Module contents ---------------- - -.. automodule:: GPy.plotting.matplot_dep.latent_space_visualizations - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/GPy.plotting.matplot_dep.rst b/doc/source/GPy.plotting.matplot_dep.rst index 77780708..9521d9e6 100644 --- a/doc/source/GPy.plotting.matplot_dep.rst +++ b/doc/source/GPy.plotting.matplot_dep.rst @@ -6,31 +6,15 @@ Subpackages .. toctree:: - GPy.plotting.matplot_dep.latent_space_visualizations + GPy.plotting.matplot_dep.controllers Submodules ---------- -GPy.plotting.matplot_dep.Tango module -------------------------------------- +GPy.plotting.matplot_dep.defaults module +---------------------------------------- -.. automodule:: GPy.plotting.matplot_dep.Tango - :members: - :undoc-members: - :show-inheritance: - -GPy.plotting.matplot_dep.base_plots module ------------------------------------------- - -.. automodule:: GPy.plotting.matplot_dep.base_plots - :members: - :undoc-members: - :show-inheritance: - -GPy.plotting.matplot_dep.dim_reduction_plots module ---------------------------------------------------- - -.. automodule:: GPy.plotting.matplot_dep.dim_reduction_plots +.. automodule:: GPy.plotting.matplot_dep.defaults :members: :undoc-members: :show-inheritance: @@ -43,14 +27,6 @@ GPy.plotting.matplot_dep.img_plots module :undoc-members: :show-inheritance: -GPy.plotting.matplot_dep.inference_plots module ------------------------------------------------ - -.. automodule:: GPy.plotting.matplot_dep.inference_plots - :members: - :undoc-members: - :show-inheritance: - GPy.plotting.matplot_dep.kernel_plots module -------------------------------------------- @@ -75,18 +51,10 @@ GPy.plotting.matplot_dep.maps module :undoc-members: :show-inheritance: -GPy.plotting.matplot_dep.models_plots module --------------------------------------------- +GPy.plotting.matplot_dep.plot_definitions module +------------------------------------------------ -.. automodule:: GPy.plotting.matplot_dep.models_plots - :members: - :undoc-members: - :show-inheritance: - -GPy.plotting.matplot_dep.netpbmfile module ------------------------------------------- - -.. automodule:: GPy.plotting.matplot_dep.netpbmfile +.. automodule:: GPy.plotting.matplot_dep.plot_definitions :members: :undoc-members: :show-inheritance: @@ -115,6 +83,14 @@ GPy.plotting.matplot_dep.svig_plots module :undoc-members: :show-inheritance: +GPy.plotting.matplot_dep.util module +------------------------------------ + +.. automodule:: GPy.plotting.matplot_dep.util + :members: + :undoc-members: + :show-inheritance: + GPy.plotting.matplot_dep.variational_plots module ------------------------------------------------- diff --git a/doc/source/GPy.plotting.plotly_dep.rst b/doc/source/GPy.plotting.plotly_dep.rst new file mode 100644 index 00000000..52642e49 --- /dev/null +++ b/doc/source/GPy.plotting.plotly_dep.rst @@ -0,0 +1,30 @@ +GPy.plotting.plotly_dep package +=============================== + +Submodules +---------- + +GPy.plotting.plotly_dep.defaults module +--------------------------------------- + +.. automodule:: GPy.plotting.plotly_dep.defaults + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.plotly_dep.plot_definitions module +----------------------------------------------- + +.. automodule:: GPy.plotting.plotly_dep.plot_definitions + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: GPy.plotting.plotly_dep + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/GPy.plotting.rst b/doc/source/GPy.plotting.rst index af035515..33c39c93 100644 --- a/doc/source/GPy.plotting.rst +++ b/doc/source/GPy.plotting.rst @@ -6,7 +6,29 @@ Subpackages .. toctree:: + GPy.plotting.gpy_plot GPy.plotting.matplot_dep + GPy.plotting.plotly_dep + +Submodules +---------- + +GPy.plotting.Tango module +------------------------- + +.. automodule:: GPy.plotting.Tango + :members: + :undoc-members: + :show-inheritance: + +GPy.plotting.abstract_plotting_library module +--------------------------------------------- + +.. automodule:: GPy.plotting.abstract_plotting_library + :members: + :undoc-members: + :show-inheritance: + Module contents --------------- diff --git a/doc/source/GPy.testing.rst b/doc/source/GPy.testing.rst index 9ee1e34b..a10c3d18 100644 --- a/doc/source/GPy.testing.rst +++ b/doc/source/GPy.testing.rst @@ -164,6 +164,14 @@ GPy.testing.pickle_tests module :undoc-members: :show-inheritance: +GPy.testing.plotting_tests module +--------------------------------- + +.. automodule:: GPy.testing.plotting_tests + :members: + :undoc-members: + :show-inheritance: + GPy.testing.prior_tests module ------------------------------ diff --git a/doc/source/conf.py b/doc/source/conf.py index c2418a34..d6220a89 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -19,7 +19,10 @@ import shlex # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +#for p in os.walk('../../GPy'): +# sys.path.append(p[0]) +sys.path.insert(0, os.path.abspath('../../')) +sys.path.insert(0, os.path.abspath('../../GPy/')) # -- General configuration ------------------------------------------------ @@ -31,29 +34,51 @@ import shlex # ones. extensions = [ 'sphinx.ext.autodoc', - 'sphinx.ext.coverage', + #'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', ] -import sys -try: - from unittest.mock import MagicMock -except: - from mock import Mock as MagicMock - -class Mock(MagicMock): - @classmethod - def __getattr__(cls, name): - return Mock() - -MOCK_MODULES = ['scipy.linalg.blas', 'blas', 'scipy.optimize', 'scipy.optimize.linesearch', 'scipy.linalg', 'scipy', 'scipy.special', 'scipy.integrate', 'scipy.io', 'scipy.stats', 'GPy.util.choleskies_cython', - 'sympy', 'sympy.utilities.iterables', 'sympy.utilities.lambdify', 'sympy.utilities', 'sympy.utilities.codegen', 'sympy.core.cache', 'sympy.core', 'sympy.parsing', 'sympy.parsing.sympy_parser', +#----- Autodoc +#import sys +#try: +# from unittest.mock import MagicMock +#except: +# from mock import Mock as MagicMock +# +#class Mock(MagicMock): +# @classmethod +# def __getattr__(cls, name): +# return Mock() +# +MOCK_MODULES = ['scipy.linalg.blas', 'blas', 'scipy.optimize', 'scipy.optimize.linesearch', 'scipy.linalg', + 'scipy', 'scipy.special', 'scipy.integrate', 'scipy.io', 'scipy.stats', + 'sympy', 'sympy.utilities.iterables', 'sympy.utilities.lambdify', + 'sympy.utilities', 'sympy.utilities.codegen', 'sympy.core.cache', + 'sympy.core', 'sympy.parsing', 'sympy.parsing.sympy_parser', 'nose', 'nose.tools'] -sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) +autodoc_mock_imports = MOCK_MODULES +# +#sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) +# +import sphinx_rtd_theme + +autodoc_default_flags = ['members', + #'undoc-members', + #'private-members', + #'special-members', + #'inherited-members', + 'show-inheritance'] +autodoc_member_order = 'groupwise' +add_function_parentheses = False +add_module_names = False +#modindex_common_prefix = ['GPy'] +show_authors = True + +# ------ Sphinx # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]#templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -68,8 +93,9 @@ master_doc = 'index' # General information about the project. project = u'GPy' -copyright = u'2015, GPy Authors' -author = u'GPy Authors' +#author = u'`Humans `_' +author = 'GPy Authors, see https://github.com/SheffieldML/GPy/graphs/contributors' +copyright = u'2015, '+author # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -119,7 +145,7 @@ exclude_patterns = [] #show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +#pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] @@ -135,12 +161,12 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +#html_theme_options = dict(sidebarwidth='20} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] @@ -164,7 +190,7 @@ html_theme = 'alabaster' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +#html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -180,20 +206,22 @@ html_static_path = ['_static'] #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - +#html_sidebars = { +# '**': ['globaltoc.html', 'localtoc.html', 'sourcelink.html', 'searchbox.html'], +# 'using/windows': ['windowssidebar.html', 'searchbox.html'], +#} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +#html_domain_indices = False # If false, no index is generated. -#html_use_index = True +#html_use_index = False # If true, the index is split into individual pages for each letter. -#html_split_index = False +html_split_index = True # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True @@ -231,7 +259,7 @@ htmlhelp_basename = 'GPydoc' # -- Options for LaTeX output --------------------------------------------- -latex_elements = { +#latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', @@ -243,15 +271,15 @@ latex_elements = { # Latex figure (float) alignment #'figure_align': 'htbp', -} +#} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'GPy.tex', u'GPy Documentation', - u'GPy Authors', 'manual'), -] +#latex_documents = [ +# (master_doc, 'GPy.tex', u'GPy Documentation', +# u'GPy Authors', 'manual'), +#] # The name of an image file (relative to this directory) to place at the top of # the title page. @@ -278,10 +306,10 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'gpy', u'GPy Documentation', - [author], 1) -] +#man_pages = [ +# (master_doc, 'gpy', u'GPy Documentation', +# [author], 1) +#] # If true, show URL addresses after external links. #man_show_urls = False @@ -292,11 +320,11 @@ man_pages = [ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'GPy', u'GPy Documentation', - author, 'GPy', 'One line description of project.', - 'Miscellaneous'), -] +#texinfo_documents = [ +# (master_doc, 'GPy', u'GPy Documentation', +# author, 'GPy', 'One line description of project.', +# 'Miscellaneous'), +#] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] diff --git a/doc/source/index.rst b/doc/source/index.rst index c35f1e3f..0994536d 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -13,13 +13,31 @@ This documentation is mostly aimed at developers interacting closely with the co The code can be found on our `Github project page `_. It is open source and provided under the BSD license. +For developers: + +- `Writing new models `_ +- `Writing new kernels `_ +- `Write a new plotting routine using gpy_plot `_ +- `Parameterization handles `_ + Contents: .. toctree:: - :maxdepth: 4 - - GPy + :maxdepth: 1 + GPy.models + GPy.kern + GPy.likelihoods + GPy.mappings + GPy.examples + GPy.util + GPy.plotting.gpy_plot + GPy.plotting.matplot_dep + GPy.core + GPy.core.parameterization + GPy.inference.optimization + GPy.inference.latent_function_inference + GPy.inference.mcmc Indices and tables ================== diff --git a/doc/source/tuto_creating_new_kernels.rst b/doc/source/tuto_creating_new_kernels.rst new file mode 100644 index 00000000..590be2d0 --- /dev/null +++ b/doc/source/tuto_creating_new_kernels.rst @@ -0,0 +1,236 @@ +******************** +Creating new kernels +******************** + +We will see in this tutorial how to create new kernels in GPy. We will also give details on how to implement each function of the kernel and illustrate with a running example: the rational quadratic kernel. + +Structure of a kernel in GPy +============================ + +In GPy a kernel object is made of a list of kernpart objects, which correspond to symetric positive definite functions. More precisely, the kernel should be understood as the sum of the kernparts. In order to implement a new covariance, the following steps must be followed + + 1. implement the new covariance as a :py:class:`GPy.kern.src.kern.Kern` object + 2. update the :py:mod:`GPy.kern.src` file + +Theses three steps are detailed below. + +Implementing a Kern object +============================== + +We advise the reader to start with copy-pasting an existing kernel and +to modify the new file. We will now give a description of the various +functions that can be found in a Kern object, some of which are +mandatory for the new kernel to work. + +Header +~~~~~~ + +The header is similar to all kernels: :: + + from .kern import Kern + import numpy as np + + class RationalQuadratic(Kern): + +:py:func:`GPy.kern.src.kern.Kern.__init__` ``(self, input_dim, param1, param2, *args)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The implementation of this function in mandatory. + +For all Kerns the first parameter ``input_dim`` corresponds to the +dimension of the input space, and the following parameters stand for +the parameterization of the kernel. + +You have to call ``super(, self).__init__(input_dim, +name)`` to make sure the input dimension and name of the kernel are +stored in the right place. These attributes are available as +``self.input_dim`` and ``self.name`` at runtime. Parameterization is +done by adding :py:class:`~GPy.core.parameterization.param.Param` +objects to ``self`` and use them as normal numpy ``array-like`` s in +your code. The parameters have to be added by calling +:py:func:`~GPy.core.parameterization.parameterized.Parameterized.link_parameters` +``(*parameters)`` with the +:py:class:`~GPy.core.parameterization.param.Param` objects as +arguments:: + + def __init__(self,input_dim,variance=1.,lengthscale=1.,power=1.): + super(RationalQuadratic, self).__init__(input_dim, 'rat_quad') + assert input_dim == 1, "For this kernel we assume input_dim=1" + self.variance = Param('variance', variance) + self.lengthscale = Param('lengtscale', lengthscale) + self.power = Param('power', power) + self.add_parameters(self.variance, self.lengthscale, self.power) + +From now on you can use the parameters ``self.variance, +self.lengthscale, self.power`` as normal numpy ``array-like`` s in your +code. Updates from the optimization routine will be done +automatically. + +:py:func:`~GPy.core.parameterization.parameter_core.Parameterizable.parameters_changed` ``(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The implementation of this function is optional. + +This functions deals as a callback for each optimization iteration. If +one optimization step was successfull and the parameters (added by +:py:func:`~GPy.core.parameterization.parameterized.Parameterized.link_parameters` +``(*parameters)``) this callback function will be called to be able to +update any precomputations for the kernel. Do not implement the +gradient updates here, as those are being done by the model enclosing +the kernel:: + + def parameters_changed(self): + # nothing todo here + pass + + +:py:func:`~GPy.kern.src.kern.Kern.K` ``(self,X,X2)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The implementation of this function in mandatory. + +This function is used to compute the covariance matrix associated with +the inputs X, X2 (np.arrays with arbitrary number of line (say +:math:`n_1`, :math:`n_2`) and ``self.input_dim`` columns). :: + + def K(self,X,X2): + if X2 is None: X2 = X + dist2 = np.square((X-X2.T)/self.lengthscale) + return self.variance*(1 + dist2/2.)**(-self.power) + +:py:func:`~GPy.kern.src.kern.Kern.Kdiag` ``(self,X)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The implementation of this function is mandatory. + +This function is similar to ``K`` but it computes only the values of +the kernel on the diagonal. Thus, ``target`` is a 1-dimensional +np.array of length :math:`n \times 1`. :: + + def Kdiag(self,X): + return self.variance*np.ones(X.shape[0]) + +:py:func:`~GPy.kern.src.kern.Kern.update_gradients_full` ``(self, dL_dK, X, X2=None)`` +~~~~~~~~~~~~~~~~~~~ + +This function is required for the optimization of the parameters. + +Computes the gradients and sets them on the parameters of this model. +For example, if the kernel is parameterized by +:math:`\sigma^2, \theta`, then + +.. math:: + + \frac{\partial L}{\partial\sigma^2} + = \frac{\partial L}{\partial K} \frac{\partial K}{\partial\sigma^2} + +is added to the gradient of :math:`\sigma^2`: ``self.variance.gradient = `` +and + +.. math:: + + \frac{\partial L}{\partial\theta} + = \frac{\partial L}{\partial K} \frac{\partial K}{\partial\theta} + +to :math:`\theta`. :: + + def update_gradients_full(self, dL_dK, X, X2): + if X2 is None: X2 = X + dist2 = np.square((X-X2.T)/self.lengthscale) + + dvar = (1 + dist2/2.)**(-self.power) + dl = self.power * self.variance * dist2 * self.lengthscale**(-3) * (1 + dist2/2./self.power)**(-self.power-1) + dp = - self.variance * np.log(1 + dist2/2.) * (1 + dist2/2.)**(-self.power) + + self.variance.gradient = np.sum(dvar*dL_dK) + self.lengthscale.gradient = np.sum(dl*dL_dK) + self.power.gradient = np.sum(dp*dL_dK) + + +:py:func:`~GPy.kern.src.kern.Kern.update_gradients_diag` ``(self,dL_dKdiag,X,target)`` +~~~~~~~~~~~~~~~~~~~ + +This function is required for BGPLVM, sparse models and uncertain inputs. + +As previously, target is an ``self.num_params`` array and + +.. math:: + + \frac{\partial L}{\partial Kdiag} + \frac{\partial Kdiag}{\partial param} + +is set to each ``param``. :: + + def update_gradients_diag(self, dL_dKdiag, X): + self.variance.gradient = np.sum(dL_dKdiag) + # here self.lengthscale and self.power have no influence on Kdiag so target[1:] are unchanged + +:py:func:`~GPy.kern.src.kern.Kern.gradients_X` ``(self,dL_dK, X, X2)`` +~~~~~~~~~~~~~~~~~~~ + +This function is required for GPLVM, BGPLVM, sparse models and uncertain inputs. + +Computes the derivative of the likelihood with respect to the inputs +``X`` (a :math:`n \times q` np.array). The result is returned by the +function which is a :math:`n \times q` np.array. :: + + def gradients_X(self,dL_dK,X,X2): + """derivative of the covariance matrix with respect to X.""" + if X2 is None: X2 = X + dist2 = np.square((X-X2.T)/self.lengthscale) + + dX = -self.variance*self.power * (X-X2.T)/self.lengthscale**2 * (1 + dist2/2./self.lengthscale)**(-self.power-1) + return np.sum(dL_dK*dX,1)[:,None] + +:py:func:`~GPy.kern.src.kern.Kern.gradients_X_diag` ``(self,dL_dKdiag,X)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This function is required for BGPLVM, sparse models and uncertain +inputs. As for ``dKdiag_dtheta``, + +.. math:: + + \frac{\partial L}{\partial Kdiag} \frac{\partial Kdiag}{\partial X} + +is added to each element of target. :: + + def gradients_X_diag(self,dL_dKdiag,X): + # no diagonal gradients + pass + +**Second order derivatives** +~~~~~~~~~~~~~~~~~~~~~~~~ + +These functions are required for the magnification factor and are the same as the first order gradients for X, but +as the second order derivatives: + +.. math:: \frac{\partial^2 K}{\partial X\partial X2} + +- :py:func:`GPy.kern.src.kern.gradients_XX` ``(self,dL_dK, X, X2)`` +- :py:func:`GPy.kern.src.kern.gradients_XX_diag` ``(self,dL_dKdiag, X)`` + +**Psi statistics** +~~~~~~~~~~~~~ + +The psi statistics and their derivatives are required for BGPLVM and +GPS with uncertain inputs only, the expressions are as follows + +- `psi0(self, Z, variational_posterior)` + .. math:: + + \psi_0 = \sum_{i=0}^{n}E_{q(X)}[k(X_i, X_i)] + +- `psi1(self, Z, variational_posterior)`:: + .. math:: + + \psi_1^{n,m} = E_{q(X)}[k(X_n, Z_m)] + +- `psi2(self, Z, variational_posterior)` + .. math:: + + \psi_2^{m,m'} = \sum_{i=0}^{n}E_{q(X)}[ k(Z_m, X_i) k(X_i, Z_{m'})] + +- `psi2n(self, Z, variational_posterior)` + .. math:: + + \psi_2^{n,m,m'} = E_{q(X)}[ k(Z_m, X_n) k(X_n, Z_{m'})] diff --git a/doc/source/tuto_creating_new_models.rst b/doc/source/tuto_creating_new_models.rst new file mode 100644 index 00000000..07f6194f --- /dev/null +++ b/doc/source/tuto_creating_new_models.rst @@ -0,0 +1,100 @@ +.. _creating_new_models: + +******************* +Creating new Models +******************* + +In GPy all models inherit from the base class :py:class:`~GPy.core.parameterized.Parameterized`. :py:class:`~GPy.core.parameterized.Parameterized` is a class which allows for parameterization of objects. All it holds is functionality for tying, bounding and fixing of parameters. It also provides the functionality of searching and manipulating parameters by regular expression syntax. See :py:class:`~GPy.core.parameterized.Parameterized` for more information. + +The :py:class:`~GPy.core.model.Model` class provides parameter introspection, objective function and optimization. + +In order to fully use all functionality of +:py:class:`~GPy.core.model.Model` some methods need to be implemented +/ overridden. And the model needs to be told its parameters, such +that it can provide optimized parameter distribution and handling. +In order to explain the functionality of those methods +we will use a wrapper to the numpy ``rosen`` function, which holds +input parameters :math:`\mathbf{X}`. Where +:math:`\mathbf{X}\in\mathbb{R}^{N\times 1}`. + +Obligatory methods +================== + +:py:func:`~GPy.core.model.Model.__init__` : + Initialize the model with the given parameters. These need to + be added to the model by calling + `self.add_parameter()`, where param needs to be a + parameter handle (See parameterized_ for details).:: + + self.X = GPy.Param("input", X) + self.add_parameter(self.X) + +:py:meth:`~GPy.core.model.Model.log_likelihood` : + Returns the log-likelihood of the new model. For our example + this is just the call to ``rosen`` and as we want to minimize + it, we need to negate the objective.:: + + return -scipy.optimize.rosen(self.X) + +:py:meth:`~GPy.core.model.Model.parameters_changed` : + Updates the internal state of the model and sets the gradient of + each parameter handle in the hierarchy with respect to the + log_likelihod. Thus here we need to set the negative derivative of + the rosenbrock function for the parameters. In this case it is the + gradient for self.X.:: + + self.X.gradient = -scipy.optimize.rosen_der(self.X) + + +Here the full code for the `Rosen` class:: + + from GPy import Model, Param + import scipy + class Rosen(Model): + def __init__(self, X, name='rosenbrock'): + super(Rosen, self).__init__(name=name) + self.X = Param("input", X) + self.add_parameter(self.X) + def log_likelihood(self): + return -scipy.optimize.rosen(self.X) + def parameters_changed(self): + self.X.gradient = -scipy.optimize.rosen_der(self.X) + +In order to test the newly created model, we can check the gradients +and optimize a standard rosenbrock run:: + + >>> m = Rosen(np.array([-1,-1])) + >>> print m + Name : rosenbrock + Log-likelihood : -404.0 + Number of Parameters : 2 + Parameters: + rosenbrock. | Value | Constraint | Prior | Tied to + input | (2,) | | | + >>> m.checkgrad(verbose=True) + Name | Ratio | Difference | Analytical | Numerical + ------------------------------------------------------------------------------------------ + rosenbrock.input[[0]] | 1.000000 | 0.000000 | -804.000000 | -804.000000 + rosenbrock.input[[1]] | 1.000000 | 0.000000 | -400.000000 | -400.000000 + >>> m.optimize() + >>> print m + Name : rosenbrock + Log-likelihood : -6.52150088871e-15 + Number of Parameters : 2 + Parameters: + rosenbrock. | Value | Constraint | Prior | Tied to + input | (2,) | | | + >>> print m.input + Index | rosenbrock.input | Constraint | Prior | Tied to + [0] | 0.99999994 | | | N/A + [1] | 0.99999987 | | | N/A + >>> print m.gradient + [ -1.91169809e-06, 1.01852309e-06] + +This is the optimium for the 2D Rosenbrock function, as expected, and +the gradient of the inputs are almost zero. + +Optional methods +================ + +Currently none. diff --git a/doc/source/tuto_parameterized.rst b/doc/source/tuto_parameterized.rst new file mode 100644 index 00000000..507ec109 --- /dev/null +++ b/doc/source/tuto_parameterized.rst @@ -0,0 +1,23 @@ +.. _parameterized: + +******************* +Parameterization handling +******************* + +Parameterization in GPy is done through so called parameter handles. The parameter handles are handles to parameters of a model of any kind. A parameter handle can be constrained, fixed, randomized and others. All parameters in GPy have a name, with which they can be accessed in the model. The most common way of accesssing a parameter programmatically though, is by variable name. + +Parameter handles +============== + +A parameter handle in GPy is a handle on a parameter, as the name suggests. A parameter can be constrained, fixed, randomized and more (See e.g. `working with models`). This gives the freedom to the model to handle parameter distribution and model updates as efficiently as possible. All parameter handles share a common memory space, which is just a flat numpy array, stored in the highest parent of a model hierarchy. +In the following we will introduce and elucidate the different parameter handles which exist in GPy. + +:py:class:`~GPy.core.parameterization.parameterized.Parameterized` +========== + +A parameterized object itself holds parameter handles and is just a summarization of the parameters below. It can use those parameters to change the internal state of the model and GPy ensures those parameters to allways hold the right value when in an optimization routine or any other update. + +:py:class:`~GPy.core.parameterization.param.Param` +=========== + +The lowest level of parameter is a numpy array. This Param class inherits all functionality of a numpy array and can simply be used as if it where a numpy array. These parameters can be accessed in the same way as a numpy array is indexed. diff --git a/doc/source/tuto_plotting.rst b/doc/source/tuto_plotting.rst new file mode 100644 index 00000000..8da53135 --- /dev/null +++ b/doc/source/tuto_plotting.rst @@ -0,0 +1,145 @@ +******************** +Defining a new plotting function in GPy +******************** + +GPy has a wrapper for different plotting backends. +There are some functions you can use for standard plotting. +Anything going beyond the scope of the +:py:class:`~GPy.plotting.abstract_plotting_library.AbstractPlottingLibrary` classes plot definitions +should be considered carefully and maybe is a special case for your plotting library only. + +All plotting related code lives in :py:mod:`GPy.plotting` and beneath. No plotting related code needs to be +anywhere else in GPy. + +As examples are always the easiest way to learn how to, we +will implement an example of a plotting function, which plots the covariance of a kernel. + +Write your plotting function into a module under :py:mod:`GPy.plotting.gpy_plot` ``.`` +using the plotting routines provided in :py:func:`GPy.plotting.plotting_library`. +I like to ``from . import plotting_library as pl`` and the allways use ``pl().`` to access functionality of +the plotting library. + +For the covariance plot we define the function in :py:mod:`GPy.plotting.kernel_plots`. + +The first thing is to define the function parameters *and write the documentation for them*! +The first argument of the plotting function is always ``self`` for the class this plotting function +will be attached to (we will get to attaching the function to a class that in detail later on):: + + def plot_covariance(kernel, x=None, label=None, + plot_limits=None, visible_dims=None, resolution=None, + projection=None, levels=20, **kwargs): + """ + Plot a kernel covariance w.r.t. another x. + + :param array-like x: the value to use for the other kernel argument (kernels are a function of two variables!) + :param plot_limits: the range over which to plot the kernel + :type plot_limits: Either (xmin, xmax) for 1D or (xmin, xmax, ymin, ymax) / ((xmin, xmax), (ymin, ymax)) for 2D + :param array-like visible_dims: input dimensions (!) to use for x. Make sure to select 2 or less dimensions to plot. + :resolution: the resolution of the lines used in plotting. for 2D this defines the grid for kernel evaluation. + :param {2d|3d} projection: What projection shall we use to plot the kernel? + :param int levels: for 2D projection, how many levels for the contour plot to use? + :param kwargs: valid kwargs for your specific plotting library + """ + +Having defined the outline of the function we can start implementing +the real plotting. + +First, we will write the necessary logic behind getting the covariance function. +This involves getting an Xgrid to plot with and the second x to compare the covariance to:: + + from .plot_util import helper_for_plot_data + X = np.ones((2, kernel.input_dim)) * [-4, 4] + _, free_dims, Xgrid, xx, yy, _, _, resolution = helper_for_plot_data(kernel, X, plot_limits, visible_dims, None, resolution) + from numbers import Number + if x is None: + x = np.zeros((1, kernel.input_dim)) + elif isinstance(x, Number): + x = np.ones((1, kernel.input_dim))*x + K = kernel.K(Xgrid, x) + +``free_dims`` holds the free dimensions after selecting +from the visible_dims, ``Xgrid`` is the grid for the covariance, +``xx, yy`` are the grid positions for 2D plotting and ``x`` is the +``X2`` for the kernel and ``K`` holds the kernel covariance for +all positions between ``Xgrid`` and ``x``. + +Then we need a canvas to plot on. Always push the keyword arguments +of the specifig library through :py:func:`GPy.plotting.abstract_plotting_library.AbstractPlottingLibrary.new_canvas`:: + + if projection == '3d': + zlabel = "k(X, {!s})" % (np.asanyarray(x).tolist()) + xlabel = 'X[:,0]' + ylabel = 'X[:,1]' + else: + xlabel = 'X' + ylabel = "k(X, {!s})" % (np.asanyarray(x).tolist()) + + canvas, kwargs = pl().new_canvas(projection=projection, xlabel=xlabel, ylabel=ylabel, zlabel=zlabel, **kwargs) + +Also very important is to use the defaults, which are defined for all plotting libraries implemented. +This is done by updating the ``kwargs`` from the defaults. There is a helper function +which takes care for existing keyword arguments. In this case we will just use the default for +plotting a mean function for the covariance plot as well. If you want to define your own defaults +add them to the defaults for each library and add it in here. See for example the defaults for +matplotlib in :py:mod:`GPy.plotting.matplot_dep.defaults`. There is also the default for the +meanplot_1d, which we are for the 1d plot:: + + from .plot_util import update_not_existing_kwargs + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_1d) # @UndefinedVariable + +The full definition of the plotting then looks like this:: + + if len(free_dims)<=2: + if len(free_dims)==1: + # 1D plotting: + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_1d) # @UndefinedVariable + plots = dict(covariance=[pl().plot(canvas, Xgrid[:, free_dims], K, label=label, **kwargs)]) + else: + if projection == '2d': + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_2d) # @UndefinedVariable + plots = dict(covariance=[pl().contour(canvas, xx[:, 0], yy[0, :], + K.reshape(resolution, resolution), + levels=levels, label=label, **kwargs)]) + elif projection == '3d': + update_not_existing_kwargs(kwargs, pl().defaults.meanplot_3d) # @UndefinedVariable + plots = dict(covariance=[pl().surface(canvas, xx, yy, + K.reshape(resolution, resolution), + label=label, + **kwargs)]) + return pl().add_to_canvas(canvas, plots) + + else: + raise NotImplementedError("Cannot plot a kernel with more than two input dimensions") + +Where we return whatever is returned by :py:func:`GPy.plotting.abstract_plotting_library.AbstractPlottingLibrary.add_to_canvas`, +so that the plotting library can choose what to do with the plot later, when we want to show it. In order +to show a plot, we can just call :py:func:`GPy.plotting.show` with the output of the plot above. + +Now we want to add the plot to the :py:class:`GPy.kern.src.kern.Kern`. In order to do that, we inject the plotting function into the +class in the :py:mod:`GPy.plotting.__init__`, which will make sure that the on the fly change of the backend +works smoothly. Thus, in :py:mod:`GPy.plotting.__init__` we add the line:: + + from ..kern import Kern + Kern.plot_covariance = gpy_plot.kernel_plots.plot_covariance + +And that's it. The plot can be shown in plotly by calling:: + + GPy.plotting.change_plotting_library('plotly') + + k = GPy.kern.RBF(1) + GPy.kern.Matern32(1) + k.randomize() + fig = k.plot() + GPy.plotting.show(fig, ) + + k = GPy.kern.RBF(2) + GPy.kern.Matern32(2) + k.randomize() + fig = k.plot() + GPy.plotting.show(fig, ) + + k = GPy.kern.RBF(1) + GPy.kern.Matern32(2) + k.randomize() + fig = k.plot(projection='3d') + GPy.plotting.show(fig, ) + +This explains the next thing. Changing the backend works *on-the-fly*. To show the above example in matplotlib, we just +exchange the first line by ``GPy.plotting.change_plotting_library('matplotlib')``. diff --git a/setup.cfg b/setup.cfg index 7fc74878..d7da653a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,3 +8,5 @@ commit = True [bdist_wheel] universal = 1 +[upload_docs] +upload-dir = doc/build/html diff --git a/setup.py b/setup.py index a81469da..1d4e7321 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # -# * Neither the name of paramax nor the names of its +# * Neither the name of GPy nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # @@ -39,18 +39,19 @@ import os import sys from setuptools import setup, Extension import numpy as np - +import codecs def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() - + with codecs.open(fname, 'r', 'latin') as f: + return f.read() + def read_to_rst(fname): try: import pypandoc - #print 'Warning in installation: For rst formatting in pypi, consider installing pypandoc for conversion' - with open('README.rst', 'w') as f: - f.write(pypandoc.convert('README.md', 'rst')) - except: + rstname = "{}.{}".format(os.path.splitext(fname)[0], 'rst') + return pypandoc.convert(read(fname), 'rst', format='md') + #return read(rstname) + except ImportError: return read(fname) version_dummy = {} @@ -70,9 +71,9 @@ else: compile_flags = [ '-fopenmp', '-O3', ] link_args = ['-lgomp'] -ext_mods = [Extension(name='GPy.kern._src.stationary_cython', - sources=['GPy/kern/_src/stationary_cython.c', - 'GPy/kern/_src/stationary_utils.c'], +ext_mods = [Extension(name='GPy.kern.src.stationary_cython', + sources=['GPy/kern/src/stationary_cython.c', + 'GPy/kern/src/stationary_utils.c'], include_dirs=[np.get_include(),'.'], extra_compile_args=compile_flags, extra_link_args = link_args), @@ -85,37 +86,47 @@ ext_mods = [Extension(name='GPy.kern._src.stationary_cython', sources=['GPy/util/linalg_cython.c'], include_dirs=[np.get_include(),'.'], extra_compile_args=compile_flags), - Extension(name='GPy.kern._src.coregionalize_cython', - sources=['GPy/kern/_src/coregionalize_cython.c'], + Extension(name='GPy.kern.src.coregionalize_cython', + sources=['GPy/kern/src/coregionalize_cython.c'], include_dirs=[np.get_include(),'.'], extra_compile_args=compile_flags)] setup(name = 'GPy', version = __version__, - author = read('AUTHORS.txt'), + author = read_to_rst('AUTHORS.txt'), author_email = "gpy.authors@gmail.com", description = ("The Gaussian Process Toolbox"), license = "BSD 3-clause", keywords = "machine-learning gaussian-processes kernels", url = "http://sheffieldml.github.com/GPy/", ext_modules = ext_mods, - packages = ["GPy.models", + packages = ["GPy", + "GPy.core", + "GPy.core.parameterization", + "GPy.kern", + "GPy.kern.src", + "GPy.kern.src.psi_comp", + "GPy.models", + "GPy.inference", "GPy.inference.optimization", "GPy.inference.mcmc", - "GPy.inference", "GPy.inference.latent_function_inference", - "GPy.likelihoods", "GPy.mappings", - "GPy.examples", "GPy.core.parameterization", - "GPy.core", "GPy.testing", - "GPy", "GPy.util", "GPy.kern", - "GPy.kern._src.psi_comp", "GPy.kern._src", - "GPy.plotting.matplot_dep.latent_space_visualizations.controllers", - "GPy.plotting.matplot_dep.latent_space_visualizations", - "GPy.plotting.matplot_dep", "GPy.plotting"], + "GPy.likelihoods", + "GPy.mappings", + "GPy.examples", + "GPy.testing", + "GPy.util", + "GPy.plotting", + "GPy.plotting.gpy_plot", + "GPy.plotting.matplot_dep", + "GPy.plotting.matplot_dep.controllers", + "GPy.plotting.plotly_dep", + ], package_dir={'GPy': 'GPy'}, package_data = {'GPy': ['defaults.cfg', 'installation.cfg', 'util/data_resources.json', 'util/football_teams.json', + 'plotting/plotting_tests/baseline/*.png' ]}, include_package_data = True, py_modules = ['GPy.__init__'], @@ -129,5 +140,34 @@ setup(name = 'GPy', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 2.7', - 'Topic :: Scientific/Engineering :: Artificial Intelligence'] + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + ] ) + + +# Check config files and settings: +local_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'GPy', 'installation.cfg')) +home = os.getenv('HOME') or os.getenv('USERPROFILE') +user_file = os.path.join(home,'.config', 'GPy', 'user.cfg') + +print("") +if not os.path.exists(user_file): + # Does an old config exist? + old_user_file = os.path.join(home,'.gpy_user.cfg') + if os.path.exists(old_user_file): + # Move it to new location: + print("GPy: Found old config file, moving to new location {}".format(user_file)) + os.rename(old_user_file, user_file) + else: + # No config file exists, save informative stub to user config folder: + print("GPy: Saving user configuration file to {}".format(user_file)) + if not os.path.exists(os.path.dirname(user_file)): + os.makedirs(os.path.dirname(user_file)) + with open(user_file, 'w') as f: + with open(local_file, 'r') as l: + tmp = l.read() + f.write(tmp) +else: + print("GPy: User configuration file at location {}".format(user_file)) \ No newline at end of file diff --git a/travis_tests.py b/travis_tests.py index d25e95d5..d034fcfd 100644 --- a/travis_tests.py +++ b/travis_tests.py @@ -2,21 +2,21 @@ # Copyright (c) 2015, Max Zwiessele # # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# +# # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# -# * Neither the name of paramax nor the names of its +# +# * Neither the name of GPy nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -31,9 +31,9 @@ #!/usr/bin/env python -import matplotlib -matplotlib.use('svg') +import matplotlib +matplotlib.use('agg') -import nose -nose.main('GPy', defaultTest='GPy/testing') +import nose +nose.main('GPy', defaultTest='GPy/testing/')