4

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)
Saeed
  • 598
  • 10
  • 19
  • @ Eric Leschinski: Although I am asking to convert it but any conversion is not acceptable since I want to see if Python has the capability to produce 3D plot like Matlab? – Saeed Apr 15 '21 at 03:24
  • @Eric Leschinski: Thank you for pointing out that page. I can make pictures on that page more beautiful than the ones on that page using Matlab:) – Saeed Apr 15 '21 at 03:31
  • @Sepide you may be interested to see my answer if you care about rendering performance – anon01 Apr 15 '21 at 03:51

3 Answers3

3

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

anon01
  • 10,618
  • 8
  • 35
  • 58
  • I usually use `ax, fig = plt.subplots()` and do what ever I want with `ax` like legend, etc. Is there any way I can do in the way I described? – Saeed Apr 15 '21 at 05:18
  • I believe plotly supports subplots, etc. The documentation is friendly and full of examples. – anon01 Apr 15 '21 at 08:08
0

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

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • Thank you for the help. I really appreciate it. Can I ask you to use one of my surfaces so that I get better idea how to follow you code snippet? – Saeed Apr 15 '21 at 03:38
0

You can also significantly improve the rendering quality by adding "dpi" spec.

For example,

fig = plt.figure(figsize=plt.figaspect(0.5), dpi=2000) 

to make it higher resolution image.

enter image description here

toyota Supra
  • 3,181
  • 4
  • 15
  • 19