matplotlib 'бар' против 'барх' участки. Проблема с бархом - PullRequest
4 голосов
/ 04 мая 2020

Я только что заметил что-то странное, и мне было интересно, кто-нибудь может объяснить, что происходит?

У меня есть словарь, я строю горизонтальные и вертикальные гистограммы из.

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

если словарь недоступен, почему он позволяет мне построить нормальную гистограмму? Это просто причудливая функция Барха или я что-то не так делаю?

Вот мой тестовый набор данных:

food = {'blueberries':2, 'pizza':3.50, 'apples':0.50}

Спасибо.

Ответы [ 2 ]

4 голосов
/ 04 мая 2020

Другой ответ, конечно, правильный в том, как решить проблему - просто преобразовать в список. Во-первых, причина, по которой он не работает, заключается в копании в исходном коде matplotlib.

bar и barh оба вызывают matplotlib.axes.Axes.bar под капотом. Когда вы строите график bar, x - это позиция x столбцов, а height - это значение y.

Однако, вызывая barh, значения y (т. Е. ['blueberries', 'pizza', 'apples']) фактически устанавливаются в аргумент bottom, а длина столбцов определяется как width.

Следующая строка вызывается в исходном коде

func(ax, *map(sanitize_sequence, args), **kwargs)

Где 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)

Проблема в том, что аргумент bottom является kwarg, и поэтому не передается sanitize_sequence и никогда не преобразуется в список. В то время как в обычном bar, x преобразуется в список на sanitize_sequence

Так что проблема в том, как barh реализован под капотом.

4 голосов
/ 04 мая 2020

Хороший MWE. Похоже, вы столкнулись с небольшой ошибкой преобразования python 2 в python 3.

Под python 2, dict.keys() (et c.) Используется для возврата списков значений. В python 3, dict.keys() возвращает представление данных, соответствующих ключам. Эта точка зрения не является хашиной (я думаю, что в принципе так и было бы; однако такое поведение не реализовано (пока)). Приведение вашего ключевого представления к списку обходит проблему:

plt.barh(list(food.keys()), food.values())

Edit

Реальный вопрос заключается в том, почему 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...