Как центрировать столбцы гистограммы вокруг делений с помощью морского дисплота? Штабелирование баров имеет важное значение

Я искал много способов сделать гистограммы, сосредоточенные вокруг делений, но не смог найти решение, которое работает с морским графиком. Функция displot позволяет мне складывать гистограмму в соответствии со столбцом в фрейме данных, и поэтому я бы предпочел решение, использующее displot или что-то, что позволяет складывать на основе столбца в фрейме данных с цветовым кодированием, как с палитрой.

Даже после установки значений делений я не могу заставить столбцы центрироваться вокруг делений.

Пример кода

# Center the histogram on the tick marks 
tips = sns.load_dataset('tips')
sns.displot(x = "total_bill",
                hue = "day", multiple = 'stack', data=tips)
plt.xticks(np.arange(0, 50, 5))


Я также хотел бы построить гистограмму переменной, которая принимает одно значение, и выбрать ширину ячейки результирующей гистограммы таким образом, чтобы она была сосредоточена вокруг значения. (0,5 в этом примере.)

Я могу получить центральную точку, выбрав количество бинов, равное количеству делений, но результирующая полоса будет очень тонкой. Как я могу увеличить размер корзины в этом случае, когда есть только одна полоса, но я хочу отобразить все остальные возможные точки. При отображении всех делений ширина полосы становится очень маленькой. Я хочу такое же центрирование полосы на отметке 0,5, но сделать ее шире, так как это единственное значение, для которого отображаются счетчики. Любые решения?

tips['single'] = 0.5
sns.displot(x='single',
                hue = "day", multiple = 'stack', data=tips, bins = 10)
plt.xticks(np.arange(0, 1, 0.1))

Редактировать: Можно ли во втором случае лучше контролировать деления? Я бы не хотел отображать округление до 1 знака после запятой, а выбрал, какую из галочек отображать. Можно ли отображать только одно значение в галочке и центрировать его вокруг него?

Относятся ли min_val и max_val в этом случае к значению переменной, которое в этом случае будет равно 0, а затем ось x будет отображаться с отрицательными значениями, даже если их нет, и они не хотят их отображать.

Отметки делений — это просто список значений, которые находятся в пределах оси. Вы можете построить их по своему желанию, и они появятся в соответствующих местах. Пожалуйста, смотрите мой отредактированный ответ для объяснения.

skuzzy 19.12.2020 07:02

Минимальное и максимальное значения были перенесены из предыдущего примера. По сути, вы должны указать диапазон, в котором должны быть рассчитаны ячейки. Кроме того, я думаю, что то, что вы действительно пытаетесь построить, является категориальной гистограммой. Так ли это?

skuzzy 19.12.2020 08:02

@skuzzy Большое спасибо за объяснение. Я не пытался построить категориальное значение, но это помогает мне увидеть логику, которую я могу использовать, когда хочу представить ограниченные значения на оси x.

Anusha 21.12.2020 04:45
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
3
6 415
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

tips = sns.load_dataset('tips')
min_val = tips.total_bill.min()
max_val = tips.total_bill.max()
val_width = max_val - min_val
n_bins = 10
bin_width = val_width/n_bins

sns.histplot(x = "total_bill",
                hue = "day", multiple = 'stack', data=tips,
                bins=n_bins, binrange=(min_val, max_val),
                palette='Paired')
plt.xlim(0, 55) # Define x-axis limits

Еще одна вещь, которую следует помнить, это то, что ширина a столбца на гистограмме определяет границы ее диапазона. Таким образом, полоса, охватывающая [2,5] по оси x, означает, что значения, представленные этой полосой, принадлежат этому диапазону.

Учитывая это, легко сформулировать решение. Предположим, что нам нужны исходные гистограммы - определение границ каждой гистограммы, одно из решений может выглядеть так:

plt.xticks(np.arange(min_val-bin_width, max_val+bin_width, bin_width))

Теперь, если мы сместим деления на половину ширины бина, мы доберемся до центров столбцов.

plt.xticks(np.arange(min_val-bin_width/2, max_val+bin_width/2, bin_width))

Для вашего графика с одним значением идея остается той же. Управляйте bin_width и диапазоном и тиками по оси X. Ширина бина должна контролироваться явно, поскольку автоматический вывод ширины бина, вероятно, будет равен 1 единице ширины, которая на графике не будет иметь толщины. Полосы гистограммы всегда указывают диапазон, даже если у нас есть только одно значение. Это показано в следующем примере и на рисунке.

single_val = 23.5
tips['single'] = single_val
bin_width = 4

fig, axs = plt.subplots(1, 2, sharey=True, figsize=(12,4)) # Get 2 subplots 

# Case 1 - With the single value as x-tick label on subplot 0
sns.histplot(x='single',
                hue = "day", multiple = 'stack', data=tips, 
                binwidth=bin_width, binrange=(single_val-bin_width, single_val+bin_width),
                palette='rocket',
                ax=axs[0])
ticks = [single_val, single_val+bin_width] # 2 ticks - given value and given_value + width
axs[0].set(
    title='Given value as tick-label starts the bin on x-axis',
    xticks=ticks,
    xlim=(0, int(single_val*2)+bin_width)) # x-range such that bar is at middle of x-axis
axs[0].xaxis.set_major_formatter(FormatStrFormatter('%.1f'))

# Case 2 - With centering on the bin starting at single-value on subplot 1
sns.histplot(x='single',
                hue = "day", multiple = 'stack', data=tips, 
                binwidth=bin_width, binrange=(single_val-bin_width, single_val+bin_width),
                palette='rocket',
                ax=axs[1])

ticks = [single_val+bin_width/2] # Just the bin center
axs[1].set(
    title='Bin centre is offset from single_value by bin_width/2',
    xticks=ticks,
    xlim=(0, int(single_val*2)+bin_width) ) # x-range such that bar is at middle of x-axis
axs[1].xaxis.set_major_formatter(FormatStrFormatter('%.1f'))

Выход:

Из вашего описания я чувствую, что то, что вы действительно подразумеваете под гистограммой, является категориальной гистограммой. Затем центрирование происходит автоматически. Потому что полоса больше не диапазон, а дискретная категория. Из-за числового и непрерывного характера переменной в данных примера я бы не рекомендовал такой подход. Pandas обеспечивает построение категориальных гистограмм. Смотрите здесь. Для нашего примера один из способов сделать это выглядит следующим образом:

n_colors = len(tips['day'].unique()) # Get number of uniques categories
agg_df = tips[['single', 'day']].groupby(['day']).agg(
    val_count=('single', 'count'),
    val=('single','max')
).reset_index() # Get aggregated information along the categories
agg_df.pivot(columns='day', values='val_count', index='val').plot.bar(
    stacked=True,
    color=sns.color_palette("Paired", n_colors), # Choose "number of days" colors from palette
    width=0.05 # Set bar width
    ) 
plt.show()

Это дает:

Спасибо за рабочее решение. Я хочу контролировать цвета и порядок их отображения. Есть ли способ сделать это с помощью histplot? Я обнаружил, что sns.displot предоставляет эту функцию, и поэтому предпочитаю что-то, что работает с displot. Я отредактировал вопрос для второй части. Решение для первой части не будет работать во второй части, так как val_width будет равно нулю. Это помогает?

Anusha 18.12.2020 09:11

цветовая схема для графика histplot также отличается от displot, а палитра не работает с histplot. Есть ли способ выбрать мои цвета для стеков? Кроме того, можно ли пометить первую точку как 0, а не 0,68?

Anusha 18.12.2020 09:14
histplot и displot имеют много общих параметров, включая palette. Вы можете обратиться к документации здесь для полной сигнатуры функции. seaborn.pydata.org/generated/seaborn.histplot.html Обратите внимание, что для маркировки ваших xticks все, что ожидается от plt.xticks, — это список значений. В моем примере я использовал arange() для создания этих значений. Вы можете назначить список переменной и просто добавить 0 в начало этого списка или изменить первый элемент, чтобы он был равен 0, прежде чем передавать его в plt.xticks(), чтобы начать с нуля. Дайте мне знать, если это решит вашу проблему.
skuzzy 18.12.2020 09:30

Что касается вашего второго вопроса, вы должны попробовать контролировать параметр bin_width вместо количества bins. Это можно сделать вместе с ограничением минимальных и максимальных значений по оси x. Тонкий график, который вы получаете, связан с тем, что a) bin_width выводится автоматически, что здесь является единичным значением. б? ось x слишком широка, чтобы секция с единичным значением была достаточно широкой.

skuzzy 18.12.2020 09:31

Я пытался добавить палитру, прежде чем оставить здесь комментарий, но не работает. Есть ли причина, по которой этот подход работает с histplot, но не с displot. Я пробовал этот подход с displot, но он не работает. Графики, которые я получаю как от histplot, так и от displot, выглядят совершенно по-разному, и я считаю, что displot показывает тенденции гораздо лучше. Это из-за масштабирования по оси Y? Любая причина, по которой histplot не соответствует стилю sns или цветовой схеме, которую я выбрал?

Anusha 18.12.2020 09:36

ValueError: min() arg - пустая последовательность: ошибка, которую я получаю при добавлении палитры как к дисплею, так и к гистплоту. Ваш подход работает и с displot. Вы знаете, как добавить палитру к этому. Это важно для графиков, которые я делаю.

Anusha 18.12.2020 09:46

Я отредактировал свой ответ на ваш второй вопрос. Не могли бы вы подробно описать вашу ошибку? Давайте перенесем это обсуждение в чат — chat.stackoverflow.com/rooms/6/python.

skuzzy 18.12.2020 09:55

Какой стиль или цвета sns/seaborn вы используете для показанных графиков? Кроме того, я думаю, что эта ошибка аргумента min() возникает из-за того, как палитра получает доступ к этим значениям для построения графика. Есть ли решение добавить палитру в код выше?

Anusha 18.12.2020 09:56

Я получаю ошибку для одиночной гистограммы. NameError: имя FormatStrFormatter не определено. Я добавил галочку и попытался определить это, но мне нужна помощь с синтаксисом.

Anusha 18.12.2020 12:27

О, вам нужно импортировать его - from matplotlib.ticker import FormatStrFormatter. Это только для форматирования меток с плавающей запятой.

skuzzy 18.12.2020 12:44

Другие вопросы по теме