[英]Grouped bar chart with multiple markers
我正在使用pandas.plot
創建分組條形圖。 我想用每個數據點兩個不同的標記覆蓋該圖表。 IRL 標記代表之前時間段的相同數據。 我知道如何使用kind='line'
和linestyle='None'
創建標記,但我不知道如何讓它們與條對齊。 所需的 output 將為每個數據點(來自下面的 MRE 中的df
)有一個彩色條,並且與該條對齊的是兩個可區分的標記,分別代表df2
和df3
。
我想創建另一個只使用標記的條形圖,但 AFAIK 是不可能的。 在這個例子中,我也陷入了使用yerr
的兔子洞: 如何在 python 的條形圖上添加標記?
但是似乎不可能為上/下錯誤生成兩個單獨的標記,這在這里是必要的。
這是我想要實現的一個簡單示例,唯一的問題是標記的 x 對齊。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
df_data = {'A':np.random.randint(20, 50, 5),
'B':np.random.randint(10, 50, 5),
'C':np.random.randint(30, 50, 5),
'D':np.random.randint(30, 100, 5)}
df2_data = {'A':np.random.randint(20, 50, 5),
'B':np.random.randint(10, 50, 5),
'C':np.random.randint(30, 50, 5),
'D':np.random.randint(30, 100, 5)}
df3_data = {'A':np.random.randint(20, 50, 5),
'B':np.random.randint(10, 50, 5),
'C':np.random.randint(30, 50, 5),
'D':np.random.randint(30, 100, 5)}
df = pd.DataFrame(data=df_data)
df2 = pd.DataFrame(data=df2_data)
df3 = pd.DataFrame(data=df3_data)
fig = plt.figure()
bar_colors = ['red', 'blue', 'green', 'goldenrod']
ax = fig.gca()
df2.plot(kind='line', ax=ax, linestyle='None', marker='^',
color=bar_colors,
markerfacecolor='white', legend=False)
df3.plot(kind='line', ax=ax, linestyle='None', marker='o',
color=bar_colors,
markerfacecolor='white', legend=False)
df.plot(kind='bar', ax=ax, color=bar_colors, width=0.8, rot=0)
plt.show()
使用pointplot
的點圖,您可以使用dodge=
來散布標記,類似於條形圖。 但是,對於pointplot
和barplot
使用的閃避寬度的解釋是不同的。 此寬度可以按照此 github 問題中的注釋進行調整。
似乎還沒有選項可以將面部顏色與標記邊緣顏色分開。 但之后可以更改它們。 此外,圖例將包括所有元素,並且可以更改為僅包含最后 4 個元素。
由於 seaborn 更喜歡“長格式”的數據幀,因此需要使用melt
。 以及為原始索引創建一個顯式列。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
df_data = {'A': np.random.randint(20, 50, 5),
'B': np.random.randint(10, 50, 5),
'C': np.random.randint(30, 50, 5),
'D': np.random.randint(30, 100, 5)}
df2_data = {'A': np.random.randint(20, 50, 5),
'B': np.random.randint(10, 50, 5),
'C': np.random.randint(30, 50, 5),
'D': np.random.randint(30, 100, 5)}
df3_data = {'A': np.random.randint(20, 50, 5),
'B': np.random.randint(10, 50, 5),
'C': np.random.randint(30, 50, 5),
'D': np.random.randint(30, 100, 5)}
df = pd.DataFrame(data=df_data)
df2 = pd.DataFrame(data=df2_data)
df3 = pd.DataFrame(data=df3_data)
bar_colors = ['red', 'blue', 'green', 'goldenrod']
dogde_width = .8 - .8 / len(bar_colors)
ax = sns.pointplot(data=df2.melt(ignore_index=False).reset_index(),
x='index', y='value', hue='variable', linestyles='', markers='^',
palette=bar_colors, dodge=dogde_width)
sns.pointplot(data=df3.melt(ignore_index=False).reset_index(),
x='index', y='value', hue='variable', linestyles='', markers='o',
palette=bar_colors, dodge=dogde_width, ax=ax)
sns.barplot(data=df.melt(ignore_index=False).reset_index(),
x='index', y='value', hue='variable',
palette=bar_colors, dodge=True, ax=ax)
handles, labels = ax.get_legend_handles_labels()
leg_num = len(bar_colors)
ax.legend(handles[-leg_num:], labels[-leg_num:]) # use only four last elements for the legend
for markers in ax.collections:
markers.set_facecolor('white')
markers.set_linewidth(1)
plt.show()
使用 matplotlibs bar() 和 scatter() 我想出了這個解決方案:
x = np.arange(len(df))
width = 0.2
fig, ax = plt.subplots()
# main dataframe
ax.bar(x - width *1.5,np.array(df["A"]),width,label="A")
ax.bar(x - width/2 ,np.array(df["B"]),width,label="B")
ax.bar(x + width/2 ,np.array(df["C"]),width,label="C")
ax.bar(x + width *1.5 ,np.array(df["D"]),width,label="D")
ax.set_xticks(x)
ax.legend()
# df2
ax.scatter(x - width *1.5,np.array(df2["A"]),c="black",marker="_",zorder=2)
ax.scatter(x - width/2,np.array(df2["B"]),c="black",marker="_",zorder=2)
ax.scatter(x + width/2,np.array(df2["C"]),c="black",marker="_",zorder=2)
ax.scatter(x + width *1.5,np.array(df2["D"]),c="black",marker="_",zorder=2)
# df3
ax.scatter(x - width *1.5,np.array(df3["A"]),c="black",marker="_",zorder=2)
ax.scatter(x - width/2,np.array(df3["B"]),c="black",marker="_",zorder=2)
ax.scatter(x + width/2,np.array(df3["C"]),c="black",marker="_",zorder=2)
ax.scatter(x + width *1.5,np.array(df3["D"]),c="black",marker="_",zorder=2)
這應該是這樣的:
您可以嘗試不同的標記和 colors。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.