如何一次性将df列值映射为十六进制颜色?

时间:2017-11-20 17:45:24

标签: python-3.x pandas matplotlib colors

我有一个包含两列的pandas数据框。其中一个列值需要映射到十六进制的颜色。另一个图形化过程从那里开始。

这是我到目前为止所尝试的。部分玩具代码取自here

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

import seaborn as sns

# Create dataframe
df = pd.DataFrame(np.random.randint(0,21,size=(7, 2)), columns=['some_value', 'another_value'])
# Add a nan to handle realworld
df.iloc[-1] = np.nan 

# Try to map values to colors in hex
# # Taken from here 
norm = matplotlib.colors.Normalize(vmin=0, vmax=21, clip=True)
mapper = plt.cm.ScalarMappable(norm=norm, cmap=plt.cm.viridis)

df['some_value_color'] = df['some_value'].apply(lambda x: mapper.to_rgba(x))
df

哪个输出:

enter image description here

如何一次性将'some_value' df列值转换为十六进制? 理想情况下使用sns.cubehelix_palette(light=1)

我不反对使用matplotlib

以外的其他内容

提前致谢。

1 个答案:

答案 0 :(得分:3)

您可以使用matplotlib.colors.to_hex()将颜色转换为十六进制表示。

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

import seaborn as sns

# Create dataframe
df = pd.DataFrame(np.random.randint(0,21,size=(7, 2)), columns=['some_value', 'another_value'])
# Add a nan to handle realworld
df.iloc[-1] = np.nan 

# Try to map values to colors in hex
# # Taken from here 
norm = matplotlib.colors.Normalize(vmin=0, vmax=21, clip=True)
mapper = plt.cm.ScalarMappable(norm=norm, cmap=plt.cm.viridis)

df['some_value_color'] = df['some_value'].apply(lambda x: mcolors.to_hex(mapper.to_rgba(x)))
df

enter image description here

<小时/>

效率

以上方法易于使用,但可能效率不高。在接下来让我们比较一些替代方案。

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

def create_df(n=10):
    # Create dataframe
    df = pd.DataFrame(np.random.randint(0,21,size=(n, 2)), 
                      columns=['some_value', 'another_value'])
    # Add a nan to handle realworld
    df.iloc[-1] = np.nan
    return df

以下是上述解决方案。它将逐行应用转换为数据帧。这效率很低。

def apply1(df):
    # map values to colors in hex via
    # matplotlib to_hex by pandas apply
    norm = mcolors.Normalize(vmin=np.nanmin(df['some_value'].values), 
                                       vmax=np.nanmax(df['some_value'].values), clip=True)
    mapper = plt.cm.ScalarMappable(norm=norm, cmap=plt.cm.viridis)

    df['some_value_color'] = df['some_value'].apply(lambda x: mcolors.to_hex(mapper.to_rgba(x)))
    return df

这就是为什么我们可能首先选择将值计算为numpy数组,然后将此数组指定为新创建的列。

def apply2(df):
    # map values to colors in hex via
    # matplotlib to_hex by assigning numpy array as column
    norm = mcolors.Normalize(vmin=np.nanmin(df['some_value'].values), 
                                       vmax=np.nanmax(df['some_value'].values), clip=True)
    mapper = plt.cm.ScalarMappable(norm=norm, cmap=plt.cm.viridis)
    a = mapper.to_rgba(df['some_value'])
    df['some_value_color'] =  np.apply_along_axis(mcolors.to_hex, 1, a)
    return df

最后,我们可以使用从matplotlib色图创建的查找表(LUT),并通过规范化数据索引LUT。由于此解决方案需要首先创建LUT,因此对于具有比LUT具有颜色的条目少的条目的数据帧而言,它是相当不可靠的,但是对于大型数据帧将获得回报。

def apply3(df):
    # map values to colors in hex via
    # creating a hex Look up table table and apply the normalized data to it
    norm = mcolors.Normalize(vmin=np.nanmin(df['some_value'].values), 
                                       vmax=np.nanmax(df['some_value'].values), clip=True)
    lut = plt.cm.viridis(np.linspace(0,1,256))
    lut = np.apply_along_axis(mcolors.to_hex, 1, lut)
    a = (norm(df['some_value'].values)*255).astype(np.int16)
    df['some_value_color'] = lut[a]
    return df

比较时间 我们来看一个10000行的数据帧。 df = create_df(10000)

  • 原始解决方案(apply1)

    %timeit apply1(df)
    2.66 s per loop
    
  • 数组解决方案(apply2)

    %timeit apply2(df)
    240 ms per loop
    
  • LUT解决方案(apply3)

    %timeit apply1(df)
    7.64 ms per loop
    

在这种情况下,LUT解决方案几乎可以提高400倍。