带有两个轴的 Matplotlib 游标值 [英] Matplotlib cursor value with two axes
问题描述
我使用 twinx()
在图上得到两个 y 轴.但是,我希望导航栏报告第一个轴的y坐标.默认情况下,它向第二个轴报告位置.您如何将其更改为报告第一个轴,或者更好的是,同时报告两个轴?
I used twinx()
to get two y-axes on the plot. However, I'd like the navigation bar to report the y-coordinates of the first axis. It seems by default, it reports the position to the second axis. How do you change it to report the first axis, or better yet, report both?
推荐答案
从tcaswell的答案中获得帮助(此处),您可以修改跟踪器以显示相对于两个轴的坐标,如下所示:
Given help from tcaswell's answers (here, and here), you could modify the tracker to display coordinates with respect to both axes like this:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
def make_format(current, other):
# current and other are axes
def format_coord(x, y):
# x, y are data coordinates
# convert to display coords
display_coord = current.transData.transform((x,y))
inv = other.transData.inverted()
# convert back to data coords with respect to ax
ax_coord = inv.transform(display_coord)
coords = [ax_coord, (x, y)]
return ('Left: {:<40} Right: {:<}'
.format(*['({:.3f}, {:.3f})'.format(x, y) for x,y in coords]))
return format_coord
np.random.seed(6)
numdata = 100
t = np.linspace(0.05, 0.11, numdata)
y1 = np.cumsum(np.random.random(numdata) - 0.5) * 40000
y2 = np.cumsum(np.random.random(numdata) - 0.5) * 0.002
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.format_coord = make_format(ax2, ax1)
ax1.plot(t, y1, 'r-', label='y1')
ax2.plot(t, y2, 'g-', label='y2')
plt.show()
或者,如果您有 scipy,您可以使用 FollowDotCursor
,它将注释最接近光标的数据点.这样,用户的眼睛不必离开图形就可以找到数据坐标.此外,它可以应用于两个以上的艺术家(只需为每条线、散点图、条形图等添加一个 FollowDotCursor).由于注释窗口显示的是最接近的数据点的值,而不只是光标在数据坐标中的坐标,因此它也更加准确.
Alternatively, if you have scipy, you could use FollowDotCursor
, which will annotate the data point closest to the cursor. Done this way, the user's eyes do not have to move far from the graph to find the data coordinates. Moreover, it can be applied to more than two artists (just add a FollowDotCursor for each line, scatter plot, bar graph, etc.).
It is also more accurate since the annotation window shows the values of the closest data point, not simply the coordinates of the cursor in data coordinates.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import scipy.spatial as spatial
def fmt(x, y):
return 'x: {x:0.2f}\ny: {y:0.2f}'.format(x=x, y=y)
class FollowDotCursor(object):
"""Display the x,y location of the nearest data point.
https://stackoverflow.com/a/4674445/190597 (Joe Kington)
https://stackoverflow.com/a/20637433/190597 (unutbu)
"""
def __init__(self, ax, x, y, formatter=fmt, offsets=(-20, 20)):
try:
x = np.asarray(x, dtype='float')
except (TypeError, ValueError):
x = np.asarray(mdates.date2num(x), dtype='float')
y = np.asarray(y, dtype='float')
mask = ~(np.isnan(x) | np.isnan(y))
x = x[mask]
y = y[mask]
self._points = np.column_stack((x, y))
self.offsets = offsets
y = y[np.abs(y - y.mean()) <= 3 * y.std()]
self.scale = x.ptp()
self.scale = y.ptp() / self.scale if self.scale else 1
self.tree = spatial.cKDTree(self.scaled(self._points))
self.formatter = formatter
self.ax = ax
self.fig = ax.figure
self.ax.xaxis.set_label_position('top')
self.dot = ax.scatter(
[x.min()], [y.min()], s=130, color='green', alpha=0.7)
self.annotation = self.setup_annotation()
plt.connect('motion_notify_event', self)
def scaled(self, points):
points = np.asarray(points)
return points * (self.scale, 1)
def __call__(self, event):
ax = self.ax
# event.inaxes is always the current axis. If you use twinx, ax could be
# a different axis.
if event.inaxes == ax:
x, y = event.xdata, event.ydata
elif event.inaxes is None:
return
else:
inv = ax.transData.inverted()
x, y = inv.transform([(event.x, event.y)]).ravel()
annotation = self.annotation
x, y = self.snap(x, y)
annotation.xy = x, y
annotation.set_text(self.formatter(x, y))
self.dot.set_offsets((x, y))
event.canvas.draw()
def setup_annotation(self):
"""Draw and hide the annotation box."""
annotation = self.ax.annotate(
'', xy=(0, 0), ha = 'right',
xytext = self.offsets, textcoords = 'offset points', va = 'bottom',
bbox = dict(
boxstyle='round,pad=0.5', fc='yellow', alpha=0.75),
arrowprops = dict(
arrowstyle='->', connectionstyle='arc3,rad=0'))
return annotation
def snap(self, x, y):
"""Return the value in self.tree closest to x, y."""
dist, idx = self.tree.query(self.scaled((x, y)), k=1, p=1)
try:
return self._points[idx]
except IndexError:
# IndexError: index out of bounds
return self._points[0]
np.random.seed(6)
numdata = 100
t = np.linspace(0.05, 0.11, numdata)
y1 = np.cumsum(np.random.random(numdata) - 0.5) * 40000
y2 = np.cumsum(np.random.random(numdata) - 0.5) * 0.002
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax1.plot(t, y1, 'r-', label='y1')
ax2.plot(t, y2, 'g-', label='y2')
cursor1 = FollowDotCursor(ax1, t, y1)
cursor2 = FollowDotCursor(ax2, t, y2)
plt.show()
这篇关于带有两个轴的 Matplotlib 游标值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!