I'm trying to have a barchart return a bar's label when clicked, but I can't find an example where this particular task has been done on a bar chart. I found this sample barchart from Matplotlib, but it doesn't have any events set up:
import matplotlib.pyplot as plt
import numpy as np
labels = ['G1', 'G2', 'G3', 'G4', 'G5']
men_means = [20, 34, 30, 35, 27]
women_means = [25, 32, 34, 20, 25]
x = np.arange(len(labels)) # the label locations
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(x - width/2, men_means, width, label='Men')
rects2 = ax.bar(x width/2, women_means, width, label='Women')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(x, labels)
ax.legend()
ax.bar_label(rects1, padding=3)
ax.bar_label(rects2, padding=3)
fig.tight_layout()
plt.show()
CodePudding user response:
First you need to add event handling to the Figure. You can do that with
fig.canvas.mpl_connect('button_press_event', onclick)
This tells matplotlib to run the function onclick
whenever you click on your figure. onclick
should have the signature
def onclick(event):
and you can access for example the x-coordinate of the mouse press using event.xdata
. In your case, if you are always plotting the bars at each integer position on the x-axis, you can transform the x-coordinate of the press to the nearest integer and access that element of your labels. You can obtain the index for that element as
idx = int(event.xdata.round())
Finally, event.inaxes
gets you the Axis-instance that you have clicked in, so you can access the axis labels with lbls = event.inaxes.get_xticklabels()
. Then you can write onclick
as
def onclick(event):
ax = event.inaxes
x = event.xdata
lbls = ax.get_xticklabels()
idx = int(x.round())
lbl = lbls[idx]
print(lbl.get_text())
to have the label of the nearest bar printed. This code will, however, still print something if you click between the bars. If you want to make sure that you are clicking a bar, you can get the rectangles used to plot the bar chart with ax.patches
and check first whether the click was actually within one of the rectangles.