带有两个轴的 Matplotlib 游标值 [英] Matplotlib cursor value with two axes

查看:76
本文介绍了带有两个轴的 Matplotlib 游标值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆