# -*- coding: utf-8 -*- """ Created on Wed Jan 12 12:30:23 2022 @author: Rene """ import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import MultipleLocator from mpl_toolkits.mplot3d import Axes3D from scipy.stats import multivariate_normal def lims(mplotlims): scale = 1.021 offset = (mplotlims[1] - mplotlims[0])*scale return mplotlims[1] - offset, mplotlims[0] + offset def plot_cube_edges(figure,xlims,ylims,zlims,the_color,the_line_width,the_line_style): figure.plot([xlims[1],xlims[1]], [ylims[0],ylims[1]], [zlims[0],zlims[0]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[1],xlims[1]], [ylims[0],ylims[1]], [zlims[1],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[0]], [ylims[0],ylims[1]], [zlims[0],zlims[0]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[0]], [ylims[0],ylims[1]], [zlims[1],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[1]], [ylims[1],ylims[1]], [zlims[0],zlims[0]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[1]], [ylims[1],ylims[1]], [zlims[1],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[1]], [ylims[0],ylims[0]], [zlims[0],zlims[0]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[1]], [ylims[0],ylims[0]], [zlims[1],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[1],xlims[1]], [ylims[1],ylims[1]], [zlims[0],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[1],xlims[1]], [ylims[0],ylims[0]], [zlims[0],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[0]], [ylims[1],ylims[1]], [zlims[0],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[0]], [ylims[0],ylims[0]], [zlims[0],zlims[1]],color = the_color,lw =the_line_width,ls = the_line_style) def plot_xy_plane(figure,xlims,ylims,zlims,the_color,the_line_width,the_line_style): figure.plot([xlims[1],xlims[1]], [ylims[0],ylims[1]], [0,0],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[0]], [ylims[0],ylims[1]], [0,0],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[1]], [ylims[0],ylims[0]], [0,0],color = the_color,lw =the_line_width,ls = the_line_style) figure.plot([xlims[0],xlims[1]], [ylims[1],ylims[1]], [0,0],color = the_color,lw =the_line_width,ls = the_line_style) the_mu = [0,0] the_sigma = [1/6,1/6] the_rho = 0.8 D = [[the_sigma[0],0],[0,the_sigma[1]]] pearson_matrix = [[1.0, the_rho], [the_rho, 1]] cov_matrix = np.matmul(D, np.matmul(pearson_matrix, D)) # Our 2-dimensional distribution will be over variables X and Y N = 125 X = np.linspace(-3*the_sigma[0]+the_mu[0], 3*the_sigma[0]+the_mu[0], N) lb_x = 1 ub_x = 3 result_X = np.where((X < lb_x) | (X > ub_x)) result_x = np.where((X > lb_x) & (X < ub_x)) Y = np.linspace(-3*the_sigma[1]+the_mu[1], 3*the_sigma[1]+the_mu[1], N) lb_y = 2 ub_y = 4 result_Y = np.where((Y < lb_y) | (Y > ub_y)) result_y = np.where((Y > lb_y) & (Y < ub_y)) X, Y = np.meshgrid(X, Y) # Pack X and Y into a single 3-dimensional array pos = np.empty(X.shape + (2,)) pos[:, :, 0] = X pos[:, :, 1] = Y # Evaluate the multivariate normal pdf mv_norm = multivariate_normal(the_mu, cov_matrix) Z = mv_norm.pdf(pos) max_Z = np.max(Z) Z_Copy = Z.copy() Z_Copy[result_X,:] = 0 Z_Copy[:,result_Y] = 0 # Evaluating the marginal distribution of x x_marg = np.linspace(-3*the_sigma[0]++the_mu[0], 3*the_sigma[0]++the_mu[0], N) x_pdf = multivariate_normal.pdf(x_marg, mean=the_mu[0], cov=cov_matrix[0,0]) x_mode_pdf = multivariate_normal.pdf(the_mu[0], mean=the_mu[0], cov=cov_matrix[0,0]) # Evaluating the marginal distribution of y y_marg = np.linspace(-3*the_sigma[1]+the_mu[1], 3*the_sigma[1]++the_mu[1], N) y_pdf = multivariate_normal.pdf(y_marg, mean=the_mu[1], cov=cov_matrix[1,1]) y_mode_pdf = multivariate_normal.pdf(the_mu[1], mean=the_mu[1], cov=cov_matrix[1,1]) # Adding the left panel with the theoretical pmf plt.rc('font', family='serif', size='8') fig = plt.figure() fig.set_figwidth(5) fig.set_figheight(5) fig.subplots_adjust(left=0.1, bottom=0, right=0.975, top=1, hspace=0, wspace=0.2) ax = fig.add_subplot(111, projection='3d') # Setting the axes limita ax.set_zlim(-max_Z,max_Z) ax.set_xlim(-3*the_sigma[0]+the_mu[0],3*the_sigma[0]+the_mu[0]) ax.set_ylim(-3*the_sigma[1]+the_mu[1],3*the_sigma[1]+the_mu[1]) # Setting the axes labels ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('Probability Density Function') # Get rid of colored axes planes ax.xaxis.pane.fill = False ax.yaxis.pane.fill = False ax.zaxis.pane.fill = False # Plot the edges the_xlims, the_ylims, the_zlims = lims(ax.get_xlim()), lims(ax.get_ylim()), lims(ax.get_zlim()) plot_cube_edges(ax,the_xlims, the_ylims, the_zlims,'darkgray',1,":") # Plot the xy-plane plot_xy_plane(ax,the_xlims, the_ylims, the_zlims,'darkgray',1,"-") # Set the rotation of the figure ax.view_init(elev=15, azim=35+90+90) # Bonus: To get rid of the grid as well: ax.grid(False) ax.xaxis.set_major_locator(MultipleLocator(0.2)) ax.yaxis.set_major_locator(MultipleLocator(0.2)) ax.zaxis.set_major_locator(MultipleLocator(2.5)) # Plotting the surface with wireframe: ax.plot_wireframe(X, Y, Z, rstride=3, cstride=3, alpha=0.8,lw=0.5,colors='black') ax.plot_surface(X, Y, Z, rstride=3, cstride=3, cmap=plt.cm.jet,alpha=0.4) # Plotting a set number of contours: n_contours = 15 levels = np.arange(0,max_Z,max_Z/n_contours) ax.contour(X, Y, Z, zdir='z', offset=the_zlims[0], colors ='black',levels=levels,linewidths=0.5) # Ploting the marginal distributions of x and y max_marg = np.max([x_pdf,y_pdf]) ratio = max_Z/max_marg ax.plot(x_marg, ratio*x_pdf,zs=the_ylims[1], zdir='y', label='curve in (x, z)',color = 'indianred') ax.plot(y_marg, ratio*y_pdf,zs=the_xlims[1], zdir='x', label='curve in (y, z)',color = 'indianred') # Plot some line at the mean values ax.plot([the_mu[0],the_mu[0]], [the_ylims[0],the_ylims[1]], [the_zlims[0],the_zlims[0]],color = 'darkgray',lw =1,ls = ':') ax.plot([the_xlims[0],the_xlims[1]],[the_mu[1],the_mu[1]], [the_zlims[0],the_zlims[0]],color = 'darkgray',lw =1,ls = ':') ax.plot([the_mu[0],the_mu[0]], [the_ylims[1],the_ylims[1]], [the_zlims[0],ratio*x_mode_pdf],color = 'darkgray',lw =1,ls = ':') ax.plot([the_xlims[1],the_xlims[1]],[the_mu[1],the_mu[1]], [the_zlims[0],ratio*y_mode_pdf],color = 'darkgray',lw =1,ls = ':') # adding a title to the plot text_str = 'Bivariate Normal pdf' ax.text2D(0.25, 0.9, text_str, transform=ax.transAxes,size=15) bbox = fig.bbox_inches.from_bounds(0, 0.5, 5, 4) plt.savefig("Bivariate_Normal_pdf_2.png", bbox_inches=bbox, dpi=300)