1
votes

I have a scatter 3d plot using matplotlib.

What I'm trying to do is to position the legend inside the plot. I have read the documentation and it seems that is only possible to select predefined positions or only specify x and y coordinates.

Is there a way to position the legend specifying the 3 coordinates?

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#more code
ax.legend(loc=(0.5,0.5,0.5), frameon=0)

The last line is what I thought might work but obviously is not working.

This is what I've now: This is what I have now

I'm trying to position the legend inside the axes, sort of like: The sought outcome

I reached that position by trial and error using ax.legend(loc=(0.15,0.65),frameon=0) because the legend doesn't move as the axes are rotated. The issue is that I'll be doing several plots thus I'm trying to avoid the trial and error approach.

Thanks.

1
It is not possible to position the legend in 3D coordinates. Since the legend is a 2D object anyways, what would be the desired outcome? - ImportanceOfBeingErnest
Thanks. The desired outcome would be, using the axes coordinate system, to select the position of the legend box within the axes. At the moment the only way to place the legend box inside the axes is using the options center and its variants as value for the loc parameter. But in my case that is not where Im trying to place the legend. - Arraval
I think using text could be an option but it seems to much work for such a simple task. - Arraval
What is the expected outcome and why does ax.legend(loc=(0.5,0.5), frameon=0) not do exactly what you want? - ImportanceOfBeingErnest

1 Answers

1
votes

To place the legend in a 3D plot using data coordinates, one may first get the projected coordinates of a point in 3D space using

mpl_toolkits.mplot3d.proj3d.proj_transform(x,y,z, ax.get_proj())

and provide those to the bbox_to_anchor argument of the legend. Than changing the bbox_transform to the data coordinate system produces the desired plot.

The following places the lower left corner of the legend at position (70,1000,80) in data coordinates.

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D, proj3d
import numpy as np

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = 25 * r * np.sin(theta)
y = 350* r * np.cos(theta)
ax.plot(x, y, 70*z, label='parametric curve')
ax.plot(x*.6, y*0.5, 70*z, label='parametric curve 2')

f = lambda x,y,z: proj3d.proj_transform(x,y,z, ax.get_proj())[:2]
ax.legend(loc="lower left", bbox_to_anchor=f(70,1000,80), 
          bbox_transform=ax.transData)

plt.show()

enter image description here