I have a problem with shifting the label of z axis in z direction (along the axis) in 3d plot. I want to have the label of Z-axis at its end. I found that it should be possible for example by ax.zaxis.set_label_coords(0,0,10) but it does not work.
I am using the following code to generate the plot:
from mpl_toolkits.mplot3d import Axes3D
%matplotlib notebook
fig = plt.figure(figsize=(10,7))
ax = fig.gca(projection='3d')
ax.xaxis.set_rotate_label(False)
ax.set_xlabel(r'$X$',fontsize=16,rotation=0)
ax.set_xlim3d(0, 9)
ax.yaxis.set_rotate_label(False)
ax.set_ylabel(r'$Y$',fontsize=16,rotation=0)
ax.set_ylim3d(0.35, 0.58)
ax.zaxis.set_rotate_label(False)
ax.set_zlabel(r'$Z$',fontsize=16,rotation=0, labelpad=5)
ax.zaxis.set_label_coords(0,0,10)
ax.set_zlim3d(0, 10)
ax.view_init(elev=30., azim=220)
plt.show()
Though I have no idea why set_label_coords() doesn't work in 3d plot, you can use ax.text() instead to draw the z label.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10,7))
ax = fig.gca(projection='3d')
ax.xaxis.set_rotate_label(False)
ax.set_xlabel(r'$X$',fontsize=16,rotation=0)
ax.set_xlim3d(0, 9)
ax.yaxis.set_rotate_label(False)
ax.set_ylabel(r'$Y$',fontsize=16,rotation=0)
ax.set_ylim3d(0.35, 0.58)
ax.zaxis.set_rotate_label(False)
ax.set_zlabel(r'$Z$',fontsize=16,rotation=0, labelpad=5)
ax.set_zlim3d(0, 10)
ax.text(x=-1, y=0.58, z=11, s="z", color='red', size=8)
ax.view_init(elev=30., azim=220)
plt.show()
There are already some questions about set_label_coords() in 3d plot, but none gives a reason why it doesn't work.
matplotlib - How to adjust position of axis labels in 3D plots
set_label_position no effect in 3d?
Related
I make 3d plots with matplotlib and I always get a weird frame with a normalized scale around my plot. Where does it come from and how can I get rid of it ?
Here is an example code that drives me to the problem :
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
x = np.linspace(0,10)
y = np.linspace(0,10)
z = np.linspace(0,10)
# ------------- Figure ---------------
fig, ax = plt.subplots(figsize = (9,6))
ax = fig.gca(projection='3d')
ax.plot(np.sin(x), np.cos(y), z)
plt.show()
And here is the result :
I use plt.subplots() because I want a figure with a 3D and a 2D plot side by side.
You call plt.subplots(...) and this, of course, instantiates an Axes, complete of horizontal and vertical spines, before Matplotlib is informed that you want a 3D enabled Axes.
When you later call plt.gca(...) it's too late…
Simply use
fig, ax = plt.subplots(figsize = (9,6), subplot_kw={"projection" : "3d"})
or
fig = plt.figure(figsize = (9,6))
ax = fig.add_subplot(111, projection='3d')
Addressing OP's comment
Figure.add_subplot is pretty flexible…
fig = plt.figure()
fig.add_subplot(1,5,(1,4), projection='3d')
fig.add_subplot(1,5,5)
fig.tight_layout()
plt.show()
from mpl_toolkits.mplot3d import Axes3D
ax.scatter(X_lda[:,0], X_lda[:,1], X_lda[:,2], alpha=0.4, c=y_train, cmap='rainbow', s=20)
plt.legend()
plt.show()
Essentially I'd like to add a legend for the scatterplot that shows the unique values in y_train and what color point it corresponds to on the plot.
The output plot:
Producing either a legend or a colorbar for a scatter is usually quite simple:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
x,y,z = (np.random.normal(size=(300,4))+np.array([0,2,4,6])).reshape(3,400)
c = np.tile([1,2,3,4], 100)
fig, ax = plt.subplots(subplot_kw=dict(projection="3d"))
sc = ax.scatter(x,y,z, alpha=0.4, c=c, cmap='rainbow', s=20)
plt.legend(*sc.legend_elements())
plt.colorbar(sc)
plt.show()
I have multiple plots that have the same x-axis. I would like to stack them in a report and have everything line up. However, matplotlib seems to resize them slightly based on the y tick label length.
Is it possible to force the plot area and location to remain the same across plots, relative to the pdf canvas to which I save it?
import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0.,2.,0.00001)
ys1=np.sin(xs*10.) #makes the long yticklabels
ys2=10.*np.sin(xs*10.)+10. #makes the short yticklabels
fig=plt.figure() #this plot ends up shifted right on the canvas
plt.plot(xs,ys1,linewidth=2.0)
plt.xlabel('x')
plt.ylabel('y')
fig=plt.figure() #this plot ends up further left on the canvas
plt.plot(xs,ys2,linewidth=2.0)
plt.xlabel('x')
plt.ylabel('y')
Your problem is a little unclear, however plotting them as subplots in the same figure should gaurantee that the axes and figure size of the two subplots will be alligned with each other
import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0.,2.,0.00001)
ys1=np.sin(xs*10.) #makes the long yticklabels
ys2=10.*np.sin(xs*10.)+10. #makes the short yticklabels
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.plot(xs,ys1,linewidth=2.0)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax2.plot(xs,ys2,linewidth=2.0)
ax2.set_xlabel('x')
ax2.set_ylabel('y')
plt.subplots_adjust(hspace=0.3) # adjust spacing between plots
plt.show()
This produces the following figure:
I had the same problem. The following works for me.
Force the same figure width for all your plots around all your python scripts, for example:
fig1 = plt.figure(figsize=(12,6))
...
fig2 = plt.figure(figsize=(12,4))
And do not use (very important!):
fig.tight_layout()
Save the figure
plt.savefig('figure.png')
Plot areas should now be the same.
using subplots with the same x-axis should do the trick.
use sharex=True when you create the subplots. The benefit of sharex is that zooming or panning on 1 subplot will also auto-update on all subplots with shared axes.
import numpy as np
import matplotlib.pyplot as plt
xs = np.arange(0., 2., 0.00001)
ys1 = np.sin(xs * 10.) # makes the long yticklabels
ys2 = 10. * np.sin(xs * 10.) + 10. # makes the short yticklabels
fig, (ax1, ax2) = plt.subplots(2, sharex=True)
ax1.plot(xs, ys1, linewidth=2.0)
ax1.xlabel('x')
ax1.ylabel('y')
ax2.plot(xs, ys2, linewidth=2.0)
ax2.xlabel('x')
ax2.ylabel('y')
plt.show()
Hey I cannot figure out any solution to solve my problem. The first tick labels keep overlapping. I found some methods to pad the tick label, but they did not work for a 3D plot.
Is there any way to solve this?
You can directly position and give the tick labels. If you are short on size consider setting the ticks yourself (alignment, position, names, font size, etc.). The following example does this for the Y axis tick labels:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')
x,y,z = np.random.randint(0,100,30),np.random.randint(0,100,30),np.random.randint(0,100,30)
ax.scatter(x,y,z)
ax.set_xlabel('X')
ax.set_xlim3d(0, 100)
ax.set_ylabel('Y')
ax.set_ylim3d(0, 100)
ax.set_yticks([30,60,90])
ax.set_yticklabels(['number 30','number 60','number 90'], va='center', ha='left',fontsize=24)
ax.set_zlabel('Z')
ax.set_zlim3d(0, 100)
plt.show()
, this results in:
Obviously you'll need to see what works for the figure size you want and the values you want to be shown in your plot.
I want to use a scatter plot to describe the relationship between X, Y and Z. Z is p-value so it is better to denote it as log values.
Following the instructions here, I can plot a logarithmic scatter plot, but the color bar seems wrong. The color bar is almost totally blue, but there should be some red! Below is the figure and my codes.
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import LogNorm
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.set_title("P-value")
Z1 = pos_spearmanr['pval']
X = pos_spearmanr['X']
Y = pos_spearmanr['Y']
im = ax1.scatter(X,
Y,
edgecolors=None,
c=Z1,
norm=LogNorm(),
cmap=plt.get_cmap('bwr'), alpha=0.2)
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
cbar = fig.colorbar(im,ax=ax1)