Моя цель - показать гистограмму с 3-мерными данными, x, категориальными и y1, y2 в виде непрерывных рядов; столбцы должны иметь высоту от y1 и цвет для обозначения y2.
Это не кажется мне особенно неясным, но я не нашел простого / встроенного способа использовать гистограмму для визуализации трех измерений - я думаю, в основном, для исследовательских целей, прежде чем исследовать отношения более формально.
Мне не хватает типа заговора в библиотеках? Есть ли хорошая альтернатива показу трехмерных данных?
В любом случае, вот некоторые вещи, которые я пробовал, которые не особенно удовлетворяют:
![enter image description here](https://i.stack.imgur.com/DEXZ5.png)
Некоторые данные для этих попыток
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Example data with explicit (-ve) correlation in the two series
n = 10; sd = 2.5
fruits = [ 'Lemon', 'Cantaloupe', 'Redcurrant', 'Raspberry', 'Papaya',
'Apricot', 'Cherry', 'Durian', 'Guava', 'Jujube']
np.random.seed(101)
cost = np.random.uniform(3, 15, n)
harvest = 50 - (np.random.randn(n) * sd + cost)
df = pd.DataFrame(data={'fruit':fruits, 'cost':cost, 'harvest':harvest})
df.sort_values(by="cost", inplace=True) # preferrable to sort during plot only
# set up several subplots to show progress.
n_colors = 5; cmap_base = "coolwarm" # a diverging map
fig, axs = plt.subplots(3,2)
ax = axs.flat
Попытка 1 использует hue
для 3-х затемненных данных в barplot
. Тем не менее, это дает один цвет для каждого значения в серии, а также, кажется, делает странные вещи с шириной полосы и интервалом.
import seaborn as sns
sns.barplot(ax=ax[0], x='fruit', y='cost', hue='harvest',
data=df, palette=cmap_base)
# fix the sns barplot label orientation
ax[0].set_xticklabels(ax[0].get_xticklabels(), rotation=90)
Попытка 2 использует панд DataFrame.plot.bar
, с непрерывным цветовым диапазоном, затем добавляет цветовую шкалу (необходимо скалярное отображение). Я позаимствовал некоторые техники из среднего поста среди других.
import matplotlib as mpl
norm = mpl.colors.Normalize(vmin=min(df.harvest), vmax=max(df.harvest), clip=True)
mapper1 = mpl.cm.ScalarMappable(norm=norm, cmap=cmap_base)
colors1 = [mapper1.to_rgba(x) for x in df.harvest]
df.plot.bar(ax=ax[1], x='fruit', y='cost', color=colors1, legend=False)
mapper1._A = []
plt.colorbar(mapper1, ax=ax[1], label='havest')
Попытка 3 основывается на этом, заимствуя у https://gist.github.com/jakevdp/91077b0cae40f8f8244a для облегчения дискретной цветовой карты.
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map"""
# from https://gist.github.com/jakevdp/91077b0cae40f8f8244a
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
cmap_disc = discrete_cmap(n_colors, cmap_base)
mapper2 = mpl.cm.ScalarMappable(norm=norm, cmap=cmap_disc)
colors2 = [mapper2.to_rgba(x) for x in df.harvest]
df.plot.bar(ax=ax[2], x='fruit', y='cost', color=colors2, legend=False)
mapper2._A = []
cb = plt.colorbar(mapper2, ax=ax[2], label='havest')
cb.set_ticks(np.linspace(*cb.get_clim(), num=n_colors+1)) # indicate color boundaries
cb.set_ticklabels(["{:.0f}".format(t) for t in cb.get_ticks()]) # without too much precision
Наконец, попытка 4 поддается пробованию 3d в одном сюжете и присутствует в 2 частях.
sns.barplot(ax=ax[4], x='fruit', y='cost', data=df, color='C0')
ax[4].set_xticklabels(ax[4].get_xticklabels(), rotation=90)
sns.regplot(x='harvest', y='cost', data=df, ax=ax[5])
(1) непригоден для использования - я явно не использую его по назначению. (2) нормально с 10 сериями, но с большим количеством серий сложнее определить, например, выше или ниже среднего данная выборка. (3) довольно неплохо и хорошо масштабируется до 50 баров, но это далеко не «из коробки», слишком сложное для быстрого анализа. Более того, sm._A = []
выглядит как хак, но код не работает без него. Возможно, решение в нескольких строках в (4) - лучший путь.
Возвращаясь к вопросу еще раз: возможно ли легко составить гистограмму, которая отображает 3D данные? Я сосредоточился на использовании небольшого количества цветов для третьего измерения, чтобы упростить идентификацию тенденций, но я открыт для других предложений.
Я также опубликовал решение, которое использует много пользовательского кода для достижения того, во что я не могу поверить, не встроено в некоторую графическую библиотеку Python.
редактирование:
следующий код, использующий R ggplot
, дает разумное приближение к (2) со встроенными командами.
ggplot(data = df, aes(x =reorder(fruit, +cost), y = cost, fill=harvest)) +
geom_bar(data=df, aes(fill=harvest), stat='identity') +
scale_fill_gradientn(colours=rev(brewer.pal(7,"RdBu")))
Первые 2 строки являются более или менее минимальным кодом для барплота, а третья меняет цветовую палитру.
Так что, если бы эта легкость была доступна в python, я бы хотел узнать об этом!