matplotlib - How to selectively label bars using plt.bar_label()? - Stack Overflow

When drawing a bar plot in matplotlib using bars = plt.bar(...), the returned object can be passedto

When drawing a bar plot in matplotlib using bars = plt.bar(...), the returned object can be passed to plt.bar_label(bars, labels) for easy labelling.

plt.bar_label(bars, labels) labels all of the bars. I want to only label a subset (the first three), ideally using plt.bar_label(). I don't want to invoke plt.text() or plt.annotate().

Is there a way of slicing out the bars I want from bars, and only having those labelled using plt.bar_label()?


Example below shows the default behaviour where all bars get labelled.

#Imports
import matplotlib.pyplot as plt
import pandas as pd

# Data for testing
values = [10, 9, 10.5, 4, 3.1, 2]
labels = [
    'sensor calibration', 'sensor response', 'noise floor estimate',
    'noise floor theta', 'weighted response coef', 'linear estimate'
]

#Bar plot with labels
ax = plt.figure(figsize=(5, 2)).add_subplot()
bars = ax.bar(range(6), values, color='lightgray')
ax.set(xlabel='x', ylabel='value', title='Data')
ax.spines[['top', 'right']].set_visible(False)

#Add all bar labels
label_kwargs = dict(rotation=90, weight='bold', fontsize=8, label_type='center')
ax.bar_label(bars, labels, **label_kwargs)

When drawing a bar plot in matplotlib using bars = plt.bar(...), the returned object can be passed to plt.bar_label(bars, labels) for easy labelling.

plt.bar_label(bars, labels) labels all of the bars. I want to only label a subset (the first three), ideally using plt.bar_label(). I don't want to invoke plt.text() or plt.annotate().

Is there a way of slicing out the bars I want from bars, and only having those labelled using plt.bar_label()?


Example below shows the default behaviour where all bars get labelled.

#Imports
import matplotlib.pyplot as plt
import pandas as pd

# Data for testing
values = [10, 9, 10.5, 4, 3.1, 2]
labels = [
    'sensor calibration', 'sensor response', 'noise floor estimate',
    'noise floor theta', 'weighted response coef', 'linear estimate'
]

#Bar plot with labels
ax = plt.figure(figsize=(5, 2)).add_subplot()
bars = ax.bar(range(6), values, color='lightgray')
ax.set(xlabel='x', ylabel='value', title='Data')
ax.spines[['top', 'right']].set_visible(False)

#Add all bar labels
label_kwargs = dict(rotation=90, weight='bold', fontsize=8, label_type='center')
ax.bar_label(bars, labels, **label_kwargs)
Share Improve this question edited Nov 21, 2024 at 17:44 MuhammedYunus asked Nov 20, 2024 at 12:04 MuhammedYunusMuhammedYunus 5,1452 gold badges3 silver badges16 bronze badges 0
Add a comment  | 

2 Answers 2

Reset to default 1

An easy option would be to provide empty labels for the bars that shouldn't be labeled:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# Data for testing
values = [10, 9, 10.5, 4, 3.1, 2]
labels = [
    'sensor calibration', 'sensor response', 'noise floor estimate',
    'noise floor theta', 'weighted response coef', 'linear estimate'
]

# Bar plot with labels
fig, ax = plt.subplots(figsize=(5, 3))
bars = ax.bar(range(6), values, color='lightgray')
ax.set(xlabel='x', ylabel='value', title='Data')
ax.spines[['top', 'right']].set_visible(False)

# Add centered bar labels
k = 3
label_kwargs = dict(rotation=90, weight='bold', fontsize=8, label_type='center')
ax.bar_label(bars, labels[:k] + [''] * (len(bars) - k), **label_kwargs)

plt.show()

Here is a variant that places centered labels for the long bars, and top labels for the shorter bars:

# Bar plot with labels
fig, ax = plt.subplots(figsize=(5, 3))
bars = ax.bar(range(6), values, color='lightgray')
ax.set(xlabel='x', ylabel='value', title='Data')
ax.spines[['top', 'right']].set_visible(False)

cutoff = 5  # bars higher will get centered labels, lower bars get labels on top
# Add the centered bar labels
label_kwargs = dict(rotation=90, weight='bold', fontsize=8, label_type='center')
ax.bar_label(bars, ['' if val <= cutoff else lbl for val, lbl in zip(values, labels)], **label_kwargs)
# Add bar labels at the top of the other bars
label_kwargs['label_type'] = 'edge'
label_kwargs['padding'] = 2
ax.bar_label(bars, ['' if val > cutoff else lbl for val, lbl in zip(values, labels)], **label_kwargs)

plt.show()

You can slice out the bars you want, but then you have to re-encapsulate them in a BarContainer. The resulting object can be passed to plt.bar_label() as before.

#bars = <from OP's code>

#Only label the first k bars
from matplotlib.container import BarContainer
k = 3

# Slice out the required bars & their values, and
#   re-encapsulate in a `BarContainer`
bars_k = BarContainer(bars[:k], datavalues=bars.datavalues[:k])
labels_k = labels[:k]

#Use bar_label() as before
ax.bar_label(bars_k, labels_k, **label_kwargs)

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742359173a4429045.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信