0

In order to create a 3d plot using plot_surface and wireframe I wrote this (looking here around)

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.ticker import MultipleLocator
import matplotlib.ticker as mticker
import numpy as np
from matplotlib.ticker import FormatStrFormatter

def log_tick_formatter(val, pos=None):
    return f"10$^{{{int(val)}}}$" 



data=np.genfromtxt('jpdfomegal2_90.dat')

x_len= len(np.unique(data[:, 0]))
y_len= len(np.unique(data[:, 1]))

X = data[:, 0].reshape(x_len, y_len)
Y = data[:, 1].reshape(x_len, y_len)
Z = data[:, 2].reshape(x_len, y_len)

#identify lowest non-negative Z value Zmin>0

Zmin = np.where(Z > 0, Z, np.inf).min()
Zmax = Z.max()


#and substitute zero with a slightly lower value than Zmin
Z[Z==0] = 0.9 * Zmin
#log transformation because the conversion in 3D 
#does not work well in matplotlib
Zlog = np.log10(Z)
rc('font',family='palatino')
rc('font',size=18)
fig = plt.figure(figsize=(12,8))
#ax = fig.add_subplot(projection='3d') 
ax = Axes3D(fig)
ax.set_xlim3d(0,15)
ax.set_zlim3d(np.floor(np.log10(Zmin))-1, np.ceil(np.log10(10)))
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))

rc('font',family='palatino')
rc('font',size=18)
tmp_planes = ax.zaxis._PLANES 
ax.zaxis._PLANES = ( tmp_planes[2], tmp_planes[3], 
                     tmp_planes[0], tmp_planes[1], 
                     tmp_planes[4], tmp_planes[5])

ax.set_xlabel('$\omega^2 /<\omega^2>$')
ax.xaxis.labelpad = 10
ax.yaxis.labelpad = 10
ax.set_ylabel('cos$(\omega,\lambda^2)$')

ax.zaxis.set_rotate_label(False)  # disable automatic rotation

ax.zaxis.labelpad = 10
ax.set_zlabel('')

ax.view_init(elev=17, azim=-60)

ax.grid(False)
ax.xaxis.pane.set_edgecolor('black')
ax.yaxis.pane.set_edgecolor('black')
ax.zaxis.pane.set_edgecolor('black')
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False



ax.xaxis.set_major_locator(MultipleLocator(2))
ax.yaxis.set_major_locator(MultipleLocator(0.2))
ax.zaxis.set_major_locator(MultipleLocator(1))

#not sure this axis scaling routine is really necessary 
scale_x = 1
scale_y = 1
scale_z = 0.8
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([scale_x, scale_y, scale_z, 1]))
ax.contour(X, Y, np.log10(Z), 4, lw=0.1, colors="k", linestyles="--", offset=np.floor(np.log10(Zmin))-1)#-7)
surf = ax.plot_surface(X, Y, np.log10(Z), cmap="binary", lw=0.1,alpha=0.5)
ax.plot_wireframe(X, Y, np.log10(Z),linewidth=1,color='k')
ax.contour(X, Y, np.log10(Z), 4, lw=0.1, colors="k", linestyles="solid")
fig.colorbar(surf, shrink=0.5, aspect=20)

plt.tight_layout()
plt.savefig('jpdf_lambda2_90.png', bbox_inches='tight')
plt.show()

the problem is related to the "minorticks" along zaxis .. I obtain this :enter image description here

but I would have this format and ticks in the axis enter image description here

Does somebody clarify how to obtain it and as well I did not find a way to use the log scale in pyplot 3d

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Drudox lebowsky
  • 1,020
  • 7
  • 21

1 Answers1

1

There's an open bug on log-scaling in 3D plots, and it looks like there won't be a fix any time soon.

You can use a matplotlib.ticker.FixedLocator to add the z-axis minor ticks, as shown below.

I didn't have your data, so I've plotted an arbitrary surface.

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.ticker import MultipleLocator, FixedLocator
import matplotlib.ticker as mticker
import numpy as np
from matplotlib.ticker import FormatStrFormatter

def log_tick_formatter(val, pos=None):
    return f"10$^{{{int(val)}}}$" 


x = np.linspace(1,15,15)
y = np.linspace(0,1,15)

X, Y = np.meshgrid(x, y)

Z = 1 + X**2 * Y**2

#identify lowest non-negative Z value Zmin>0
Zmin = np.where(Z > 0, Z, np.inf).min()
Zmax = Z.max()

#and substitute zero with a slightly lower value than Zmin
Z[Z==0] = 0.9 * Zmin

rc('font',family='palatino')
rc('font',size=18)
fig = plt.figure(figsize=(12,8))
ax = Axes3D(fig, auto_add_to_figure=False)
fig.add_axes(ax)

ax.set_xlim3d(0,15)
ax.set_zlim3d(np.floor(np.log10(Zmin))-1, np.ceil(np.log10(Zmax)))
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))

tmp_planes = ax.zaxis._PLANES 
ax.zaxis._PLANES = ( tmp_planes[2], tmp_planes[3], 
                     tmp_planes[0], tmp_planes[1], 
                     tmp_planes[4], tmp_planes[5])

ax.set_xlabel('$\omega^2 /<\omega^2>$')
ax.xaxis.labelpad = 10
ax.yaxis.labelpad = 10
ax.set_ylabel('cos$(\omega,\lambda^2)$')

ax.zaxis.set_rotate_label(False)  # disable automatic rotation

ax.zaxis.labelpad = 10
ax.set_zlabel('')

ax.view_init(elev=17, azim=-60)

ax.grid(False)
ax.xaxis.pane.set_edgecolor('black')
ax.yaxis.pane.set_edgecolor('black')
ax.zaxis.pane.set_edgecolor('black')
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False

ax.xaxis.set_major_locator(MultipleLocator(2))

ax.yaxis.set_major_locator(MultipleLocator(0.2))

ax.zaxis.set_major_locator(MultipleLocator(1))

# Z minor ticks
zminorticks = []
zaxmin, zaxmax = ax.get_zlim()
for zorder in np.arange(np.floor(zaxmin),
                        np.ceil(zaxmax)):
    zminorticks.extend(np.log10(np.linspace(2,9,8)) + zorder)
ax.zaxis.set_minor_locator(FixedLocator(zminorticks))

#not sure this axis scaling routine is really necessary 
scale_x = 1
scale_y = 1
scale_z = 0.8
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([scale_x, scale_y, scale_z, 1]))

ax.contour(X, Y, np.log10(Z), 4, colors="k", linestyles="--", offset=np.floor(np.log10(Zmin))-1)#-7)

surf = ax.plot_surface(X, Y, np.log10(Z), cmap="binary", lw=0.1,alpha=0.5)

ax.plot_wireframe(X, Y, np.log10(Z),linewidth=1,color='k')
ax.contour(X, Y, np.log10(Z), 4, colors="k", linestyles="solid")
fig.colorbar(surf, shrink=0.5, aspect=20)

# get a warning that Axes3D is incompatible with tight_layout()
# plt.tight_layout()

# for saving
# fig.savefig('log3d.png')

plt.show()

enter image description here

Rory Yorke
  • 2,166
  • 13
  • 13