这是一种直接使用 matplotlib 的 barh 函数来做你想做的事情的方法。这个想法是迭代地设置水平堆叠条并同时分配适当的颜色。以下是您提供的代码的改编版,用于执行我上面描述的操作:
import matplotlib.pyplot as mpl
import matplotlib.cm as mcm
import pandas as pd
import numpy as np
from typing import List, Tuple
def read_to_df(file_path: str) -> pd.DataFrame:
return pd.read_excel(file_path, index_col = 0)
def color_to_hex(color: Tuple[float]) -> str:
color = [i * 255 if i * 255 <= 255 else i * 255 - 1
for i in color[:-1]]
color = [int(round(i)) for i in color]
return "#%02x%02x%02x" % tuple(color)
def cmap_to_colors(cmap: str,
amount: int) -> List[str]:
cmap = mcm.get_cmap(cmap)
colors = [color_to_hex(cmap(i)) for i in np.linspace(0, 1, amount)]
return colors
def main() -> None:
df = read_to_df("age_dist_median_six.xlsx")
df_age_only = df.drop(["median", "youngest", "oldest"], axis = 1)
# transpose the dataframe
df_age_only = df_age_only.iloc[::-1]
colors = cmap_to_colors("viridis", 6)
fig=mpl.figure(figsize=(12,12))
N_teams=len(df_age_only)
for i in range(N_teams):
x_pos=0
for column,j in zip(df_age_only,range(len(colors))):
col_max=df_age_only.idxmax(axis='columns')[i]
if df_age_only[col_max][i]==df_age_only[column][i]:
if j==0:
mpl.barh(i,df_age_only[column][i],color=colors[j],align='center',edgecolor='k')
elif j>0:
mpl.barh(i,df_age_only[column][i],color=colors[j],left=x_pos,align='center',edgecolor='k')
else:
if j==0:
mpl.barh(i,df_age_only[column][i],color='tab:grey',align='center',edgecolor='k')
elif j>0:
mpl.barh(i,df_age_only[column][i],color='tab:grey',left=x_pos,align='center',edgecolor='k')
x_pos+=df_age_only[column][i]
mpl.yticks(np.arange(N_teams),df_age_only.index,fontsize=9)
#Setting up legend:
for i in range(len(colors)):
mpl.plot([],[],color=colors[i],lw=10,label=str(df_age_only.keys()[i]))
mpl.legend()
mpl.show()
mpl.savefig("stacked_six_viridis.png")
if __name__ == "__main__":
main()
输出给出:
或者,如果您想保留原始颜色但突出显示具有最大值的条形,您可以通过改变 alpha 值来更改条形的透明度。见以下代码:
import matplotlib.pyplot as mpl
import matplotlib.cm as mcm
import pandas as pd
import numpy as np
from typing import List, Tuple
def read_to_df(file_path: str) -> pd.DataFrame:
return pd.read_excel(file_path, index_col = 0)
def color_to_hex(color: Tuple[float]) -> str:
color = [i * 255 if i * 255 <= 255 else i * 255 - 1
for i in color[:-1]]
color = [int(round(i)) for i in color]
return "#%02x%02x%02x" % tuple(color)
def cmap_to_colors(cmap: str,
amount: int) -> List[str]:
cmap = mcm.get_cmap(cmap)
colors = [color_to_hex(cmap(i)) for i in np.linspace(0, 1, amount)]
return colors
def main() -> None:
df = read_to_df("age_dist_median_six.xlsx")
df_age_only = df.drop(["median", "youngest", "oldest"], axis = 1)
# transpose the dataframe
df_age_only = df_age_only.iloc[::-1]
colors = cmap_to_colors("viridis", 6)
fig=mpl.figure(figsize=(12,12))
N_teams=len(df_age_only)
for i in range(N_teams):
x_pos=0
for column,j in zip(df_age_only,range(len(colors))):
col_max=df_age_only.idxmax(axis='columns')[i]
if df_age_only[col_max][i]==df_age_only[column][i]:
if j==0:
mpl.barh(i,df_age_only[column][i],color=colors[j],align='center',edgecolor='tab:grey',alpha=1)
elif j>0:
mpl.barh(i,df_age_only[column][i],color=colors[j],left=x_pos,align='center',edgecolor='tab:grey',alpha=1)
else:
if j==0:
mpl.barh(i,df_age_only[column][i],color=colors[j],align='center',edgecolor='tab:grey',alpha=0.3)
elif j>0:
mpl.barh(i,df_age_only[column][i],color=colors[j],left=x_pos,align='center',edgecolor='tab:grey',alpha=0.3)
x_pos+=df_age_only[column][i]
mpl.yticks(np.arange(N_teams),df_age_only.index,fontsize=9)
#Setting up legend:
for i in range(len(colors)):
mpl.plot([],[],color=colors[i],lw=10,label=str(df_age_only.keys()[i]))
mpl.legend()
mpl.show()
mpl.savefig("stacked_six_viridis.png")
if __name__ == "__main__":
main()
还有输出:
您可以更改以突出显示条形的其他内容包括 edgecolor 和 hatch。