【问题标题】:Python: Barplot colored according to a third variablePython:根据第三个变量着色的条形图
【发布时间】:2021-03-13 14:20:36
【问题描述】:

目前我正在尝试创建一个 Barplot 来显示每周应用程序的评论量。然而,该条应根据包含每周评论的平均评分(范围:1 到 5)的第三个变量进行着色。

我按照以下帖子的说明创建了图表:Python: Barplot with colorbar

代码运行良好:

# Import Packages
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable 

# Create Dataframe
data = [[1, 10, 3.4], [2, 15, 3.9], [3, 12, 3.6], [4, 30,1.2]] 
df = pd.DataFrame(data, columns = ["week", "count", "score"])

# Convert to lists
data_x = list(df["week"])
data_hight = list(df["count"])
data_color = list(df["score"])

#Create Barplot:
data_color = [x / max(data_color) for x in data_color]
fig, ax = plt.subplots(figsize=(15, 4))

my_cmap = plt.cm.get_cmap('RdYlGn')
colors = my_cmap(data_color)
rects = ax.bar(data_x, data_hight, color=colors)

sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(1,5))
sm.set_array([])

cbar = plt.colorbar(sm)
cbar.set_label('Color', rotation=270,labelpad=25)

plt.show()

现在问题来了:您可能会注意到第 4 周的平均分值为“1.2”。然而,条形图确实表明该值位于“2.5”左右。我知道这源于以下代码行,它通过将值除以最大值来标准化值:

data_color = [x / max(data_color) for x in data_color]

不幸的是,我无法以颜色与分数的绝对值相似的方式更改此命令,例如平均得分为 1.2,最后一个条应为深红色而不是浅橙色。我试图只插入常规分数值(未标准化)来解决问题,但是,这样做会创建所有具有相同绿色的条...由于这只是我的第二个 python 项目,我很难理解这件事背后的过程,非常感谢任何建议或解决方案。

干杯尼尔

【问题讨论】:

    标签: python matplotlib data-visualization bar-chart colorbar


    【解决方案1】:

    您正确地确定了规范化是这里的问题。它位于链接代码中,由有价值的 SO 用户 @ImportanceOfBeingEarnest 为间隔 [0, 1] 定义。如果你想要另一个归一化范围[normmin, normmax],你必须在归一化过程中考虑到这一点:

    # Import Packages
    import pandas as pd
    import matplotlib.pyplot as plt
    from matplotlib.cm import ScalarMappable 
    
    # Create Dataframe
    data = [[1, 10, 3.4], [2, 15, 3.9], [3, 12, 3.6], [4, 30,1.2]] 
    df = pd.DataFrame(data, columns = ["week", "mycount", "score"])
      
    # Not necessary to convert to lists, pandas series or numpy array is also fine
    data_x = df.week
    data_hight = df.mycount
    data_color = df.score
    
    #Create Barplot:
    normmin=1
    normmax=5
    data_color = [(x-normmin) / (normmax-normmin) for x in data_color] #see the difference here
    fig, ax = plt.subplots(figsize=(15, 4))
    
    my_cmap = plt.cm.get_cmap('RdYlGn')
    colors = my_cmap(data_color)
    rects = ax.bar(data_x, data_hight, color=colors)
    
    sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(normmin,normmax))
    sm.set_array([])
    
    cbar = plt.colorbar(sm)
    cbar.set_label('Color', rotation=270,labelpad=25)
    
    plt.show()
    

    样本输出:

    显然,这不会检查所有值是否确实在[normmin, normmax] 范围内,因此更好的脚本会确保所有值都符合此规范。或者,我们可以通过裁剪超出规范化范围的值来解决这个问题:

    #...
    import numpy as np
    #.....
    #Create Barplot:
    normmin=1
    normmax=3.5
    
    data_color = [(x-normmin) / (normmax-normmin) for x in np.clip(data_color, normmin, normmax)]
    #....
    

    您可能还注意到我介绍的另一项更改。您不必提供列表 - pandas 系列或 numpy 数组也可以。如果您将列命名为不像 count 这样的 pandas 函数,您可以使用 df.ABC 而不是 df["ABC"] 来访问它们。

    【讨论】:

    • 不可能有更好的解决方案,尤其是解释。该代码现在可以正常工作了!
    猜你喜欢
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 1970-01-01
    • 2021-02-12
    相关资源
    最近更新 更多