You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib水平柱状图正负值颜色统一异常问题求助

解决Matplotlib水平柱状图正负值颜色不区分问题

问题描述

尝试用Matplotlib绘制包含正负值的水平柱状图,期望负值柱子显示红色、正值显示青色,但只要数据集中存在负值,所有柱子都会变成红色,无法实现按值区分颜色。相关代码如下:

df = df.groupby('price').agg(quantity=('quantity','sum'), 
                                            t_count=('price','size') 
                                            ).dropna(how='any').sort_index(ascending=True)

# example output of the groupby
#         quantity  t_count bar_colors
# price
# 9.05         -10            2        red
# 9.09          10            1        red
# 9.15       -1304            6        red
# 9.17         -91            2        red
# 9.18        -202            1        red
# 9.19         100            1        cyan
# 9.25        1596           10        cyan

plt.style.use('dark_background')
plt.rcParams.update({'font.size': 12}) # set font size to 12
df['bar_colors'] = np.where(df['quantity'] < 0, 'red', 'cyan')
ax = df.plot.barh(color=df['bar_colors'])

# Add count as text to the end of each bar
for i, (_, row)in enumerate(df.iterrows()):
    ax.text(row['quantity'] / 2, 
            i, 
            f"{row['t_count']}", 
            ha='center', 
            va='baseline', 
            color='white')

ax.set_xlabel('Quantity')
ax.set_ylabel('Price')
ax.legend(labels=[])
plt.show()

问题原因

pandas的DataFrame.plot.barh()方法中,color参数的作用是按数据列分配颜色,而非按单个柱子(行)分配。由于这里仅绘制quantity一列数据,color会直接取列表中的第一个颜色(红色),并将其应用到所有柱子上,忽略后续的颜色值。

解决方法

改用Matplotlib原生的barh()函数绘制,直接为每个柱子指定对应颜色,同时手动设置y轴刻度匹配price索引值。修改后的完整代码如下:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# 数据预处理(保持原逻辑)
df = df.groupby('price').agg(
    quantity=('quantity','sum'), 
    t_count=('price','size') 
).dropna(how='any').sort_index(ascending=True)

plt.style.use('dark_background')
plt.rcParams.update({'font.size': 12})
df['bar_colors'] = np.where(df['quantity'] < 0, 'red', 'cyan')

# 改用Matplotlib原生API绘制柱状图
fig, ax = plt.subplots()
y_positions = range(len(df))
# 为每个柱子指定对应颜色
ax.barh(y_positions, df['quantity'], color=df['bar_colors'])

# 设置y轴刻度与标签,匹配price索引
ax.set_yticks(y_positions)
ax.set_yticklabels(df.index)

# 在柱子中间添加计数文本
for i, (_, row) in enumerate(df.iterrows()):
    # 根据值的正负调整文本位置,确保在柱子内部
    x_pos = row['quantity'] / 2
    ax.text(x_pos, 
            i, 
            f"{row['t_count']}", 
            ha='center', 
            va='center',
            color='white')

ax.set_xlabel('Quantity')
ax.set_ylabel('Price')
ax.legend(labels=[])
plt.show()

说明

  • 原生barh()支持直接传入颜色列表,每个元素对应一个柱子的颜色,实现按值区分颜色的需求。
  • 手动设置y轴刻度是因为原生API不会自动将DataFrame的索引作为y轴标签,需要显式指定。
  • 将文本垂直对齐方式改为va='center',让计数文本更居中显示在柱子内部。

内容的提问来源于stack exchange,提问作者John Holmes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:36:25