我刚刚注意到一些奇怪的事情,想知道是否有人可以解释发生了什么?
我有一本字典,我正在从中绘制水平和垂直条形图。
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)
谢谢。
不错的 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)
另一个答案在如何解决问题方面当然是正确的 - 只需转换为列表即可。它首先不起作用的原因涉及深入研究 matplotlib 源代码。
bar并在引擎盖下进行barh调用matplotlib.axes.Axes.bar。绘制 a 时bar,x是条形的 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在幕后实施。
| 归档时间: |
|
| 查看次数: |
424 次 |
| 最近记录: |