matplotlib 'bar' 与 'barh' 图。barh 的问题

Noo*_*der 5 python matplotlib

我刚刚注意到一些奇怪的事情,想知道是否有人可以解释发生了什么?

我有一本字典,我正在从中绘制水平和垂直条形图。

plt.bar(food.keys(), food.values()) #works fine, but:
plt.barh(food.keys(), food.values() #gives "unhashable type: 'dict_keys'" error.
Run Code Online (Sandbox Code Playgroud)

如果字典是不可散列的,为什么它让我绘制一个普通的条形图?这只是 barh 函数的一个怪癖还是我做错了什么?

这是我的测试数据集:

food = {'blueberries':2, 'pizza':3.50, 'apples':0.50}
Run Code Online (Sandbox Code Playgroud)

谢谢。

Pau*_*sen 6

不错的 MWE。看起来您遇到了一个微妙的 python 2 到 python 3 转换错误。

在python 2下,dict.keys()(等)用于返回值列表。在python 3下,dict.keys()返回key对应数据的视图。这个观点是不可哈希的(我认为原则上是可以的;但是,这种行为还没有实现(还))。将您的关键视图强制转换为列表可以绕过这个问题:

plt.barh(list(food.keys()), food.values())
Run Code Online (Sandbox Code Playgroud)

编辑

真正的问题是为什么plt.bar两者都有效,plt.bar并且在幕后plt.barh调用matplotlib.axes.Axes.bar。 字面上的定义barh是:

def barh(self, y, width, height=0.8, left=None, *, align="center",
         **kwargs):
    kwargs.setdefault('orientation', 'horizontal')
    patches = self.bar(x=left, height=height, width=width, bottom=y,
                       align=align, **kwargs)
    return patches
Run Code Online (Sandbox Code Playgroud)


Dav*_*idG 6

另一个答案在如何解决问题方面当然是正确的 - 只需转换为列表即可。它首先不起作用的原因涉及深入研究 matplotlib 源代码。

bar并在引擎盖下进行barh调用matplotlib.axes.Axes.bar。绘制 a 时barx是条形的 x 位置,height是 y 值。

但是,调用 a 时barh,y 值(即['blueberries', 'pizza', 'apples'])实际上设置为参数bottom,条形的长度由 给出width

在源代码中调用以下行

func(ax, *map(sanitize_sequence, args), **kwargs)
Run Code Online (Sandbox Code Playgroud)

在哪里sanitize_sequence

def sanitize_sequence(data):
    """
    Convert dictview objects to list. Other inputs are returned unchanged.
    """
    return (list(data) if isinstance(data, collections.abc.MappingView)
            else data)
Run Code Online (Sandbox Code Playgroud)

问题是参数bottom是一个 kwarg,因此不会传递给sanitize_sequence并且永远不会转换为列表。而在正常情况下bar, ,x被转换为列表sanitize_sequence

所以问题在于如何barh在幕后实施。