我是Python新手编程的新手。我正在开发一个涉及3D表面图的项目,我希望在鼠标点击的情况下获得3D表面上的点的坐标。我已经尝试在线检查类似的东西,我已经找到了一个简洁的方法来做2D图。 (data tip for 2D plots)
我的问题是这可以扩展为3D图吗?我的直觉是我可以从表面图获得类似于link中给出的解决方案的x,y坐标,这取决于当前视图可以映射到3D坐标点(听起来是否合适?) 。但是,我无法找到办法。
答案 0 :(得分:0)
好的,我找到了解决方案!可能对某人有用,所以在这里发布。它是stack Overflow的两个解决方案的组合。
我使用了ax.format_coord(x,y)来获取z值。使用ax.format_coord(mouseevent.xdata,mouseevent.ydata),您可以获得字符串中的x,y,z值('x = 0.222,y = 0.452,z = 0.826'),您可以从中提取值。({ {3}})
def getz(x,y,ax):
s = ax.format_coord(x,y)
out = ""
for i in range(s.find('z')+2,len(s)-1):
out = out+s[i]
return float(out)
class DataCursor(object):
"""A simple data cursor widget that displays the x,y location of a
matplotlib artist when it is selected."""
def __init__(self, artists, tolerance=5, offsets=(-20, 20),
template='z: %0.2f', display_all=False):
"""Create the data cursor and connect it to the relevant figure.
"artists" is the matplotlib artist or sequence of artists that will be
selected.
"tolerance" is the radius (in points) that the mouse click must be
within to select the artist.
"offsets" is a tuple of (x,y) offsets in points from the selected
point to the displayed annotation box
"template" is the format string to be used. Note: For compatibility
with older versions of python, this uses the old-style (%)
formatting specification.
"display_all" controls whether more than one annotation box will
be shown if there are multiple axes. Only one will be shown
per-axis, regardless.
"""
self.template = template
self.offsets = offsets
self.display_all = display_all
if not cbook.iterable(artists):
artists = [artists]
self.artists = artists
self.axes = tuple(set(art.axes for art in self.artists))
self.figures = tuple(set(ax.figure for ax in self.axes))
self.annotations = {}
for ax in self.axes:
self.annotations[ax] = self.annotate(ax)
for artist in self.artists:
artist.set_picker(tolerance)
for fig in self.figures:
fig.canvas.mpl_connect('pick_event', self)
def annotate(self, ax):
"""Draws and hides the annotation box for the given axis "ax"."""
annotation = ax.annotate(self.template, xy=(0, 0), ha='right',
xytext=self.offsets, textcoords='offset points', va='bottom',
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')
)
annotation.set_visible(False)
return annotation
def __call__(self, event):
"""Intended to be called through "mpl_connect"."""
# Rather than trying to interpolate, just display the clicked coords
# This will only be called if it's within "tolerance", anyway.
x, y = event.mouseevent.xdata, event.mouseevent.ydata
z = getz(x,y,self.axes[0]) # Just a small change here.
# print str(x) + ' ' + str(y) + ' ' + str(z)
annotation = self.annotations[event.artist.axes]
if x is not None:
if not self.display_all:
# Hide any other annotation boxes...
for ann in self.annotations.values():
ann.set_visible(False)
# Update the annotation in the current axis..
annotation.xy = x, y
annotation.set_text(self.template % (z))
annotation.set_visible(True)
event.canvas.draw()
if __name__ == '__main__':
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
plt.figure()
ax = Axes3D(fig)
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1)
DataCursor([surf])
plt.show()
希望这会有所帮助。谢谢!