Make 3d Python plot as beautiful as Matlab

Viewed 1301

Note: This is not a conversion question. It is meant to see if Python has the capability to produce 3D plot like Matlab.

I have created a Matlab plot as follows: enter image description here

I tried to plot it using Python but I could not get it as good as Matlab. Is there any packages that can plot the above as good as the original one? If it is please convert my code to a Python version. Here is my Matlab code.

set(groot,'defaultAxesTickLabelInterpreter','latex');  
set(groot,'defaulttextinterpreter','latex');
set(groot,'defaultLegendInterpreter','latex');
x0=0;
y0=0;
width=3000;
height=2000;
set(gcf,'position',[x0,y0,width,height])
[X,Y] = meshgrid(-1:.01:1);
a = 3;
b = 2;
Z = a*X.^2 + b*Y.^2;
subplot(1,3,1)
s = surf(X,Y,Z,'FaceColor','r', 'FaceAlpha',0.5, 'EdgeColor','none');
s.EdgeColor = 'none';
xlabel('$x_1$','Interpreter','latex','FontSize', 15)
ylabel('$x_2$','Interpreter','latex','FontSize', 15)
zlabel('$f(\mathbf{x};\mathbf{\theta})$','Interpreter','latex','FontSize', 15)
legend({'$f([x_1, x_2]^\top; [\theta_1=3,\theta_2=2]^\top)=3x_1^2+2x_2^2$'},'interpreter','latex','FontSize', 10)
subplot(1,3,2)
Z2 = a*X.^2 ;
s2 = surf(X,Y,Z2,'FaceColor','b', 'FaceAlpha',0.5, 'EdgeColor','none');
s2.EdgeColor = 'none';
xlabel('$x_1$','Interpreter','latex','FontSize', 15)
ylabel('$x_2$','Interpreter','latex','FontSize', 15)
zlabel('$f(\mathbf{x};\mathbf{\theta})$','Interpreter','latex','FontSize', 15)
legend({'$f([x_1, x_2]^\top; [\theta_1=3,\theta_2=0]^\top)=3x_1^2$'},'interpreter','latex','FontSize', 10)
subplot(1,3,3)
s3 = surf(X,Y,Z,'FaceColor','r', 'FaceAlpha',0.5, 'EdgeColor','none');
s3.EdgeColor = 'none';
hold
s4 = surf(X,Y,Z2,'FaceColor','b', 'FaceAlpha',0.5, 'EdgeColor','none');
s4.EdgeColor = 'none';
xlabel('$x_1$','Interpreter','latex','FontSize', 15)
ylabel('$x_2$','Interpreter','latex','FontSize', 15)
zlabel('$f(\mathbf{x};\mathbf{\theta})$','Interpreter','latex','FontSize', 15)
legend({'$f(\mathbf{x};\mathbf{\theta})=3x_1^2+2x_2^2$', '$f(\mathbf{x};\mathbf{\theta})=3x_1^2$'},'interpreter','latex','FontSize', 10)
2 Answers

Yes.

numpy + plotly is an effective Matlab replacement - you may recognize some of the code :). As a benefit, the plots render as html, which means they are highly portable, save as a single file, and can be embedded in a webpage. There may be small details that are different (I don't know the current status of latex axis labels), but, provided you have python, numpy and plotly installed, the following is a good replacement of your first plot:

import plotly.graph_objects as go
import numpy as np

x = np.arange(-1,1,.01)
y = np.arange(-1,1,.01)
X,Y = np.meshgrid(x,y)
a = 3
b = 2
Z = a*X**2 + b*Y**2

fig = go.Figure(
    data=[go.Surface(z=Z, x=x, y=y, colorscale="Reds", opacity=0.5)])
fig.update_layout(
    title='My title', 
    autosize=False,
    width=500, 
    height=500,
    margin=dict(l=65, r=50, b=65, t=90), 
    scene_aspectmode='cube'
)
fig.show()

Notice that the go-to plotting package in python is Matplotlib. IMO, it inherited all the worst parts of Matlab's plotting and none of the good (performant rendering). Plotly superior from a performance (esp 3D rendering), interactivity, and API standpoint.

enter image description here

For 3D charting in Python I've had the best results with matplotlib.pyplot.

#!/usr/bin/python3 
# -*- coding: utf-8 -*-   
import matplotlib.pyplot as plt  
from mpl_toolkits.mplot3d.axes3d import Axes3D, get_test_data  
from matplotlib import cm   
import numpy as np   
import random  
X_k_list = range(1, 100, 10)  
Y_p_list = [ float(x)/100.0 for x in range(1, 100, 10) ]   
# set up a figure twice as wide as it is tall  
fig = plt.figure(figsize=plt.figaspect(0.5))  
# set up the axes for the first plot  
ax = fig.add_subplot(1, 1, 1, projection='3d')  
# plot a 3D surface like in the example mplot3d/surface3d_demo  
X, Y = np.meshgrid(X_k_list, Y_p_list)  
def critical_function(b, c):  
    num = random.uniform(0, 1) * 10.0  
    return num + (b * c)   
  
Z_accuracy = X.copy()  
Z_accuracy = Z_accuracy.astype(np.float32)  
for i in range(len(X_k_list)):  
    for j in range(len(Y_p_list)):  
        Z_accuracy[j][i] = critical_function(Y_p_list[j], X_k_list[i])  
  
surf = ax.plot_surface(X, Y, Z_accuracy,   
    rstride=1, cstride=1, cmap=cm.coolwarm,  
    linewidth=0, antialiased=False)  
  
ax.set_xlabel('X')  
ax.set_ylabel('Y')  
ax.set_zlabel('Z')  
fig.colorbar(surf, shrink=0.5, aspect=10)  
plt.show()  

https://www.python-graph-gallery.com/371-surface-plot

enter image description here

You can increase the smoothness of the chart by adding more datapoints, rotate the graph along the x,y,z axis, with the mouse and you can add a title, legend and other eye candy.

matplotlib.mplot3d looks like it does euclidian continuous surfaces

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 
from mpl_toolkits.mplot3d import axes3d 
import matplotlib.pyplot as plt 
from matplotlib import cm 
ax = plt.figure().add_subplot(projection='3d') 
X, Y, Z = axes3d.get_test_data(0.05) 
cset = ax.contour(X, Y, Z, extend3d=True, cmap=cm.coolwarm) 
ax.clabel(cset, fontsize=9, inline=True) 
plt.show() 

https://matplotlib.org/stable/gallery/mplot3d/contour3d_2.html#sphx-glr-gallery-mplot3d-contour3d-2-py

enter image description here

You're using matlab's meshgrid(...) tool to generate x,y,z data. Python can achieve the same results with numpy.meshgrid fed into matplotlib.pyplot thustly.

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 
import numpy as np 
import matplotlib.pyplot as plt 
def f(x, y): 
    return np.sin(np.sqrt(x ** 2 + y ** 2)) 
x = np.linspace(-6, 6, 30) 
y = np.linspace(-6, 6, 30) 
X, Y = np.meshgrid(x, y) 
Z = f(X, Y) 
fig = plt.figure() 
ax = plt.axes(projection='3d') 
ax.contour3D(X, Y, Z, 50, cmap='binary') 
ax.set_xlabel('x') 
ax.set_ylabel('y') 
ax.set_zlabel('z') 
plt.show() 

https://jakevdp.github.io/PythonDataScienceHandbook/04.12-three-dimensional-plotting.html

enter image description here

Related