1

I have tried to make it but while executing, it shows me the following error:

bar,=plt.bar(xpos,revenue)

ValueError: too many values to unpack

how can i solve it as i want values of x and y in the annotate while hover mouse. This is my following code:

import numpy as np
import matplotlib.pyplot as plt

company=['google','amazon','msft','fb']
revenue=[80,68,54,27]

fig=plt.figure()
ax=plt.subplot()

xpos=np.arange(len(company))

bar,=plt.bar(xpos,revenue)


annot = ax.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="black", ec="b", lw=2),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(ind):
    x,y = bar.get_data()
    x0 = x[ind["ind"][0]]
    y0 = y[ind["ind"][0]]
    annot.xy = (x0, y0)
    text = "({:.2g},{:.2g})".format(
        x0,y0,
    )
    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 = bar.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()
shubham bansal
  • 163
  • 1
  • 2
  • 9
  • 1
    What does the question in the title have to do with the error? What do you want to achieve with `bar, = ...`? What attempts did you make at debugging that line? – timgeb May 28 '18 at 06:50

1 Answers1

10

The error tells you that plt.bar returns a single object, which cannot be unpacked. So you need to remove the comma (,). Instead call the returned bar container something like bars = plt.bar(xpos,revenue).

You also cannot blindly copy some other solution for scatters or plots for bars. Instead you need to adapt it to the bars. So you need to go through the bars and check which of them, if any, is hovered.

See a complete solution here:

import numpy as np
import matplotlib.pyplot as plt

company=['google','amazon','msft','fb']
revenue=[80,68,54,27]

fig=plt.figure()
ax=plt.subplot()

xpos=np.arange(len(company))

bars = plt.bar(xpos,revenue)


annot = ax.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="black", ec="b", lw=2),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(bar):
    x = bar.get_x()+bar.get_width()/2.
    y = bar.get_y()+bar.get_height()
    annot.xy = (x,y)
    text = "({:.2g},{:.2g})".format( x,y )
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(0.4)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        for bar in bars:
            cont, ind = bar.contains(event)
            if cont:
                update_annot(bar)
                annot.set_visible(True)
                fig.canvas.draw_idle()
                return
    if vis:
        annot.set_visible(False)
        fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", hover)

plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 1
    As a minor improvement, seeing as bar charts are typically for categorical data it would make sense that the hover gives the actual name rather than just the index as this example shows. I have suggested this in an edit. Otherwise this is an excellent answer! – Daniel Soutar Dec 19 '18 at 15:52
  • 1
    The purpose of this answer is to show *how* to create an annotation that appears when hovering; of course everyone is free to annotate it with whatever they like. – ImportanceOfBeingErnest Dec 19 '18 at 15:58
  • This is useful thank you. Is there a way to adapt this for horizontal bar subplots? I'm having trouble going through each of my subplots. – rustynails Feb 22 '21 at 17:12