Possible to make labels appear when hovering over a point in matplotlib?

后端 未结 9 1046
清酒与你
清酒与你 2020-11-22 00:52

I am using matplotlib to make scatter plots. Each point on the scatter plot is associated with a named object. I would like to be able to see the name of an object when I ho

9条回答
  •  灰色年华
    2020-11-22 01:49

    It seems none of the other answers here actually answer the question. So here is a code that uses a scatter and shows an annotation upon hovering over the scatter points.

    import matplotlib.pyplot as plt
    import numpy as np; np.random.seed(1)
    
    x = np.random.rand(15)
    y = np.random.rand(15)
    names = np.array(list("ABCDEFGHIJKLMNO"))
    c = np.random.randint(1,5,size=15)
    
    norm = plt.Normalize(1,4)
    cmap = plt.cm.RdYlGn
    
    fig,ax = plt.subplots()
    sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)
    
    annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
                        bbox=dict(boxstyle="round", fc="w"),
                        arrowprops=dict(arrowstyle="->"))
    annot.set_visible(False)
    
    def update_annot(ind):
    
        pos = sc.get_offsets()[ind["ind"][0]]
        annot.xy = pos
        text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))), 
                               " ".join([names[n] for n in ind["ind"]]))
        annot.set_text(text)
        annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
        annot.get_bbox_patch().set_alpha(0.4)
    
    
    def hover(event):
        vis = annot.get_visible()
        if event.inaxes == ax:
            cont, ind = sc.contains(event)
            if cont:
                update_annot(ind)
                annot.set_visible(True)
                fig.canvas.draw_idle()
            else:
                if vis:
                    annot.set_visible(False)
                    fig.canvas.draw_idle()
    
    fig.canvas.mpl_connect("motion_notify_event", hover)
    
    plt.show()
    

    Because people also want to use this solution for a line plot instead of a scatter, the following would be the same solution for plot (which works slightly differently).

    import matplotlib.pyplot as plt
    import numpy as np; np.random.seed(1)
    
    x = np.sort(np.random.rand(15))
    y = np.sort(np.random.rand(15))
    names = np.array(list("ABCDEFGHIJKLMNO"))
    
    norm = plt.Normalize(1,4)
    cmap = plt.cm.RdYlGn
    
    fig,ax = plt.subplots()
    line, = plt.plot(x,y, marker="o")
    
    annot = ax.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
                        bbox=dict(boxstyle="round", fc="w"),
                        arrowprops=dict(arrowstyle="->"))
    annot.set_visible(False)
    
    def update_annot(ind):
        x,y = line.get_data()
        annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
        text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))), 
                               " ".join([names[n] for n in ind["ind"]]))
        annot.set_text(text)
        annot.get_bbox_patch().set_alpha(0.4)
    
    
    def hover(event):
        vis = annot.get_visible()
        if event.inaxes == ax:
            cont, ind = line.contains(event)
            if cont:
                update_annot(ind)
                annot.set_visible(True)
                fig.canvas.draw_idle()
            else:
                if vis:
                    annot.set_visible(False)
                    fig.canvas.draw_idle()
    
    fig.canvas.mpl_connect("motion_notify_event", hover)
    
    plt.show()

    In case someone is looking for a solution for lines in twin axes, refer to How to make labels appear when hovering over a point in multiple axis?

    In case someone is looking for a solution for bar plots, please refer to e.g. this answer.

提交回复
热议问题