如何让Seaborn Barplot条形颜色随IPO股票收益增减加深?
实现IPO股票收益条形图颜色随数值深浅变化的方法
我正在绘制IPO股票的日、周、月收益表现列表,希望条形的颜色随收益数值的增大/减小而加深。以下是我当前使用的代码:
# 我使用的调色板 color_daily = ['red' if x < 0 else 'green' for x in ipo_stocks.sort_values('Daily Return (%)')['Daily Return (%)']] color_weekly = ['red' if x < 0 else 'green' for x in ipo_stocks.sort_values('Weekly Return (%)')['Weekly Return (%)']] color_monthly = ['red' if x < 0 else 'green' for x in ipo_stocks.sort_values('Monthly Return (%)')['Monthly Return (%)']] fig, axes = plt.subplots(3, 1, figsize = (15,15)) fig_1 = sns.barplot(data = ipo_stocks.sort_values('Daily Return (%)'), x = 'Saham', y = 'Daily Return (%)', palette = color_daily, alpha = 0.8, ax = axes[0]) fig_1.set(ylim = (-50,50)) axes[0].tick_params(labelrotation = 90) axes[0].text(2,40, ('Rata-rata return hari pertama listing: ' + str(round(ipo_stocks['Daily Return (%)'].mean(), 2)) + '%'), fontsize = 15) axes[0].title.set_text('Performa Daily') fig_2 = sns.barplot(data = ipo_stocks.sort_values('Weekly Return (%)'), x = 'Saham', y = 'Weekly Return (%)', palette = color_weekly, alpha = 0.8, ax = axes[1]) fig_2.set(ylim = (-100, 300)) axes[1].tick_params(labelrotation = 90) axes[1].text(2, 250, ('Rata-rata return satu minggu setelah listing: ' + str(round(ipo_stocks['Weekly Return (%)'].mean(), 2)) + '%'), fontsize = 15) axes[1].title.set_text('Performa Weekly') fig_3 = sns.barplot(data = ipo_stocks.sort_values('Monthly Return (%)'), x = 'Saham', y = 'Monthly Return (%)', palette = color_monthly, alpha = 0.8, ax = axes[2]) fig_3.set(ylim = (-100, 400)) axes[2].tick_params(labelrotation = 90) axes[2].text(2, 300, ('Rata-rata return satu bulan setelah listing: ' + str(round(ipo_stocks['Monthly Return (%)'].mean(), 2)) + '%'), fontsize = 15) axes[2].title.set_text('Performa Monthly') plt.xticks(rotation = 90) plt.tight_layout()当前输出仅能区分正负收益的红绿色,无法实现颜色深浅随收益数值变化,恳请指导实现方法。
解决方案
核心思路
通过颜色映射(Colormap)和数值归一化实现颜色深浅与收益数值挂钩:
- 正收益:使用绿色系渐变(数值越大,颜色越深)
- 负收益:使用红色系渐变(数值越小,颜色越深)
修改后的完整代码
import seaborn as sns import matplotlib.pyplot as plt from matplotlib.colors import LinearSegmentedColormap, Normalize # 自定义正负收益的渐变配色 # 红色系:浅红到深红(对应负收益从接近0到最小值) red_cmap = LinearSegmentedColormap.from_list('red_gradient', ['#ffcccc', '#cc0000']) # 绿色系:浅绿到深绿(对应正收益从接近0到最大值) green_cmap = LinearSegmentedColormap.from_list('green_gradient', ['#ccffcc', '#009900']) def get_gradient_colors(values): """根据收益值生成渐变颜色列表""" colors = [] # 分别处理正负值的归一化范围 pos_values = values[values >= 0] neg_values = values[values < 0] # 正收益归一化 if len(pos_values) > 0: norm_pos = Normalize(vmin=0, vmax=pos_values.max()) # 负收益归一化(取绝对值) if len(neg_values) > 0: norm_neg = Normalize(vmin=neg_values.min(), vmax=0) for val in values: if val >= 0: colors.append(green_cmap(norm_pos(val)) if len(pos_values) > 0 else '#ccffcc') else: colors.append(red_cmap(norm_neg(val)) if len(neg_values) > 0 else '#ffcccc') return colors # 按收益排序数据,并生成对应渐变颜色 daily_sorted = ipo_stocks.sort_values('Daily Return (%)') color_daily = get_gradient_colors(daily_sorted['Daily Return (%)']) weekly_sorted = ipo_stocks.sort_values('Weekly Return (%)') color_weekly = get_gradient_colors(weekly_sorted['Weekly Return (%)']) monthly_sorted = ipo_stocks.sort_values('Monthly Return (%)') color_monthly = get_gradient_colors(monthly_sorted['Monthly Return (%)']) # 绘制子图,保留原逻辑仅替换调色板 fig, axes = plt.subplots(3, 1, figsize=(15,15)) fig_1 = sns.barplot(data=daily_sorted, x='Saham', y='Daily Return (%)', palette=color_daily, ax=axes[0]) fig_1.set(ylim=(-50,50)) axes[0].tick_params(labelrotation=90) axes[0].text(2,40, f'Rata-rata return hari pertama listing: {round(ipo_stocks["Daily Return (%)"].mean(), 2)}%', fontsize=15) axes[0].title.set_text('Performa Daily') fig_2 = sns.barplot(data=weekly_sorted, x='Saham', y='Weekly Return (%)', palette=color_weekly, ax=axes[1]) fig_2.set(ylim=(-100, 300)) axes[1].tick_params(labelrotation=90) axes[1].text(2, 250, f'Rata-rata return satu minggu setelah listing: {round(ipo_stocks["Weekly Return (%)"].mean(), 2)}%', fontsize=15) axes[1].title.set_text('Performa Weekly') fig_3 = sns.barplot(data=monthly_sorted, x='Saham', y='Monthly Return (%)', palette=color_monthly, ax=axes[2]) fig_3.set(ylim=(-100, 400)) axes[2].tick_params(labelrotation=90) axes[2].text(2, 300, f'Rata-rata return satu bulan setelah listing: {round(ipo_stocks["Monthly Return (%)"].mean(), 2)}%', fontsize=15) axes[2].title.set_text('Performa Monthly') plt.xticks(rotation=90) plt.tight_layout() plt.show()
关键说明
- 自定义渐变配色:通过
LinearSegmentedColormap创建从浅到深的红、绿渐变,可直接修改十六进制颜色值调整过渡效果。 - 数值归一化:
Normalize将收益值映射到[0,1]区间,确保颜色渐变幅度与数值大小成正比。 - 颜色生成逻辑:
get_gradient_colors函数分别处理正负收益,保证正收益随数值增大颜色加深,负收益随数值减小(更负)颜色加深。 - 代码优化:改用f-string简化字符串拼接,提升代码可读性。
内容的提问来源于stack exchange,提问作者Winston Mulyawan Setiabudi
相关产品推荐
相关产品推荐

