小能豆

插图(matplotlib)中的条形图在添加文本作为标签时出现问题?

py

我需要从子图中绘制插入轴上的条形图。这是生成子图和插入轴的代码(简化版本):

labels = ['A', 'B', 'C', 'D', 'E']
MAES = [np.random.rand() for i in range(len(labels))]

X = np.arange(0,4,.01)
Y = np.sin(X)

fig, axs = plt.subplots(2)
fig.suptitle('Vertically stacked subplots')
axs[0].plot(X,Y)
axs[1].bar(labels,MAES)

ax_in = axs[0].inset_axes([0.8, 0.1, 0.15, 0.15])

它生成以下输出:

1.png

但现在,我需要将 barpot 插入到 inset 中。为此,我在末尾添加了ax_in.bar(labels,MAES)。我得到的输出与以前相同,并且还出现了以下错误:

ValueError                                Traceback (most recent call last)
File /usr/local/lib/python3.8/dist-packages/matplotlib/axis.py:1506, in Axis.convert_units(self, x)
   1505 try:
-> 1506     ret = self.converter.convert(x, self.units, self)
   1507 except Exception as e:

File /usr/local/lib/python3.8/dist-packages/matplotlib/category.py:49, in StrCategoryConverter.convert(value, unit, axis)
     48 if unit is None:
---> 49     raise ValueError(
     50         'Missing category information for StrCategoryConverter; '
     51         'this might be caused by unintendedly mixing categorical and '
     52         'numeric data')
     53 StrCategoryConverter._validate_unit(unit)

ValueError: Missing category information for StrCategoryConverter; this might be caused by unintendedly mixing categorical and numeric data

The above exception was the direct cause of the following exception:

ConversionError                           Traceback (most recent call last)
Input In [120], in <cell line: 13>()
     10 axs[1].bar(labels,MAES)
     12 ax_in = axs[0].inset_axes([0.8, 0.1, 0.15, 0.15])
---> 13 ax_in.bar(labels,MAES)

File /usr/local/lib/python3.8/dist-packages/matplotlib/__init__.py:1412, in inner(ax, data, *args, **kwargs)
   1404 assert {*arg_names}.issuperset(replace_names or []) or varkwargs_name, (
   1405     "Matplotlib internal error: invalid replace_names ({!r}) for {!r}"
   1406     .format(replace_names, func.__name__))
   1407 assert label_namer is None or label_namer in arg_names, (
   1408     "Matplotlib internal error: invalid label_namer ({!r}) for {!r}"
   1409     .format(label_namer, func.__name__))
   1411 @functools.wraps(func)
-> 1412 def inner(ax, *args, data=None, **kwargs):
   1413     if data is None:
   1414         return func(ax, *map(sanitize_sequence, args), **kwargs)

File /usr/local/lib/python3.8/dist-packages/matplotlib/axes/_axes.py:2331, in bar(self, x, height, width, bottom, align, **kwargs)

File /usr/local/lib/python3.8/dist-packages/matplotlib/artist.py:252, in convert_xunits(self, x)
    250 ax = getattr(self, 'axes', None)
    251 if ax is None or ax.xaxis is None:
--> 252     return x
    253 return ax.xaxis.convert_units(x)

File /usr/local/lib/python3.8/dist-packages/matplotlib/axis.py:1508, in Axis.convert_units(self, x)
   1506     ret = self.converter.convert(x, self.units, self)
   1507 except Exception as e:
-> 1508     raise munits.ConversionError('Failed to convert value(s) to axis '
   1509                                  f'units: {x!r}') from e
   1510 return ret

ConversionError: Failed to convert value(s) to axis units: ['A', 'B', 'C', 'D', 'E']

为什么 bar 方法在轴子图中有效,而在插入轴中无效?我该如何解决此错误?


阅读 28

收藏
2024-12-03

共1个答案

小能豆

你遇到的问题是由于 matplotlib 在处理插入轴 (inset_axes) 时的 类别数据转换 出错。原因是 ax_in.bar() 试图将类别数据(labels = ['A', 'B', 'C', 'D', 'E'])传递给其 X 轴,matplotlib 在插入轴中没有正确的类别处理逻辑,因此抛出了 ValueError: Missing category information 错误。

解决方案

  1. 设置 ax_in 的 X 轴为类别类型:
    你可以通过明确地指定 ax_in 的 X 轴类型为 category 来解决这个问题。matplotlib 在默认情况下对 bar 图的类别数据(如你提供的 labels)会进行适当的转换,但是在插入轴中,由于缺乏类别信息,导致转换失败。通过明确指定 ax_in 的 X 轴为类别类型,matplotlib 会正确地处理。

  2. 调整代码:

修改代码中的 ax_in 设置,确保它能够正确处理类别数据。你可以通过以下方式来解决问题:

修改后的代码:

import numpy as np
import matplotlib.pyplot as plt

# 准备数据
labels = ['A', 'B', 'C', 'D', 'E']
MAES = [np.random.rand() for i in range(len(labels))]

X = np.arange(0, 4, .01)
Y = np.sin(X)

# 创建图表和子图
fig, axs = plt.subplots(2)
fig.suptitle('Vertically stacked subplots')

# 绘制正弦曲线
axs[0].plot(X, Y)

# 绘制条形图
axs[1].bar(labels, MAES)

# 创建插入轴
ax_in = axs[0].inset_axes([0.8, 0.1, 0.15, 0.15])

# 设置插入轴的x轴为类别数据
ax_in.set_xticks(np.arange(len(labels)))
ax_in.set_xticklabels(labels)

# 绘制插入轴中的条形图
ax_in.bar(np.arange(len(labels)), MAES)

# 显示图形
plt.show()

解释:

  1. ax_in.set_xticks(np.arange(len(labels)))
  2. 这行代码明确地为插入轴 ax_in 设置了 X 轴的刻度位置,np.arange(len(labels)) 生成的数值(0, 1, 2, 3, 4)对应于你的 labels 列表中的每个条目。

  3. ax_in.set_xticklabels(labels)

  4. 通过 set_xticklabels() 方法设置插入轴的 X 轴标签为 labels 列表中的值(即 ‘A’, ‘B’, ‘C’, ‘D’, ‘E’)。

  5. 绘制条形图

  6. 最后在插入轴上绘制条形图时,我们使用 np.arange(len(labels)) 作为 X 值,因为插入轴的 X 轴刻度已经手动设置为这些值。

总结:

这个方法通过明确设置插入轴的 X 轴为类别类型来避免了 matplotlib 的自动转换问题。通过这样做,你就能在插入轴中成功绘制条形图了。

2024-12-03