使用第三列值将颜色渐变映射到第 1 列和第 2 列的图; Matplotlib
Use a third column of values to map a color gradient to a plot of column 1 and column 2; Matplotlib
我有一个包含 3 列的数据框。我使用 df['name'] 作为 x 轴,使用 df['value1'] 作为 y 轴。我想使用第 3 列 (df['value2']) 为条形图生成颜色渐变。
正在使用的数据
df['name'] 是名字。 df['value1'] 是主要测量值。 df['value2'] 是 df['value1'] 值的置信度指标。我认为以颜色渐变显示 df['value2'] 会产生强大的视觉效果。
问题
我已经尝试了无数种方法来使用 matplotlib.colors 模块来实现这一点,但没有任何方法产生我正在寻找的结果。这是代码的基础(没有颜色映射到 df['value2'])。
输入
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.colors as colors
df = {'name': ['a','b','c','d'], 'value1': [10.1,13.3,9.5,15.1], 'value2': [1.5,2.0,3.5,1.3]}
df = pd.DataFrame(df)
print(df)
colorbar_1 = LinearSegmentedColormap.from_list('colorbar', ['#990000','#FF6666'], N=100)
df[['name','value1']].plot(kind='bar', colormap=colorbar_1 ,width=0.8, ylim=[9,16], fontsize=5)
plt.xticks(df.index,df['name'].values, rotation=90)
plt.ylim([9,16])
plt.gcf().subplots_adjust(bottom=0.15)
plt.tight_layout()
plt.savefig('test.png',dpi=600)
plt.show()
输出
name value1 value2
0 a 10.1 1.5
1 b 13.3 2.0
2 c 9.5 3.5
3 d 15.1 1.3
结果:
所需格式
[
我还生成了第 4 列,其中包含生成的十六进制代码,可用于执行手头的任务。我假设有更简单的方法合并 df['value2'] 但生成十六进制代码可能很方便?
输入
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.colors as colors
df = {'name': ['a','b','c','d'], 'value1': [10.1,13.3,9.5,15.1], 'value2': [1.5,2.0,3.5,1.3]}
df = pd.DataFrame(df)
print(df)
norm = mpl.colors.Normalize(vmin=0, vmax=16, clip=True)
mapper = plt.cm.ScalarMappable(norm=norm, cmap=plt.cm.viridis)
df['hex_code'] = df['value2'].apply(lambda x: colors.to_hex(mapper.to_rgba(x)))
print(df)
输出
name value1 value2
0 a 10.1 1.5
1 b 13.3 2.0
2 c 9.5 3.5
3 d 15.1 1.3
name value1 value2 hex_code
0 a 10.1 1.5 #482374
1 b 13.3 2.0 #472d7b
2 c 9.5 3.5 #3e4989
3 d 15.1 1.3 #481d6f
其中一个问题是,使用 df[['name', 'value1']].plot
会使 pandas 认为您希望数据框中每行有两个条,一个用于 'name',一个用于 'value1' .然后 pandas 感到困惑,因为它无法为 'name' 绘制条形并跳过这些。然后,对于 color=
参数,pandas 现在认为颜色列表中的第一种颜色用于 'name',第二种颜色用于 'value1'。
因此,首先,您需要将其命名为 df['value1'].plot()
。然后,pandas 非常喜欢使用索引作为 x 轴。要将 'name' 作为索引,只需将其设为数据帧的索引即可。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap, LinearSegmentedColormap, Normalize
df = {'name': ['a','b','c','d'], 'value1': [10.1,13.3,9.5,15.1], 'value2': [1.5,2.0,3.5,1.3]}
df = pd.DataFrame(df)
df.set_index('name', inplace=True)
print(df)
colormap_1 = LinearSegmentedColormap.from_list('colorbar', ['#990000','#FF6666'], N=100)
norm = Normalize(vmin=min(df['value2']), vmax=max(df['value2']))
colors = [colormap_1(norm(v)) for v in df['value2']]
df['value1'].plot(kind='bar', color=colors, width=0.8, ylim=[9,16], fontsize=5)
plt.xticks(rotation=90)
plt.ylim([9,16])
plt.tight_layout()
plt.savefig('test.png',dpi=600)
plt.show()
PS:要获得与您的链接图像相似的内容(因此不使用 'value2'),您可以尝试:
# same dataframe as before, with 'name' as index
ymin = 9
ymax = 16
barplot = df['value1'].plot(kind='bar', width=0.8, ylim=[ymin, ymax], fontsize=5)
plt.xticks(rotation=90)
gradient = np.linspace(1,0,256).reshape(256,1)
for bar in barplot.containers[0]:
bar.set_facecolor("none")
x, y = bar.get_xy()
w, h = bar.get_width(), bar.get_height()
plt.imshow(gradient, extent=[x, x + w, y + ymin, y + h], aspect="auto", cmap='bone')
plt.imshow(gradient, extent=[*plt.xlim(), *plt.ylim()] ,aspect="auto", cmap='copper_r', zorder=-1)
plt.tight_layout()
#plt.savefig('test.png',dpi=600)
plt.show()
我有一个包含 3 列的数据框。我使用 df['name'] 作为 x 轴,使用 df['value1'] 作为 y 轴。我想使用第 3 列 (df['value2']) 为条形图生成颜色渐变。
正在使用的数据
df['name'] 是名字。 df['value1'] 是主要测量值。 df['value2'] 是 df['value1'] 值的置信度指标。我认为以颜色渐变显示 df['value2'] 会产生强大的视觉效果。
问题
我已经尝试了无数种方法来使用 matplotlib.colors 模块来实现这一点,但没有任何方法产生我正在寻找的结果。这是代码的基础(没有颜色映射到 df['value2'])。
输入
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.colors as colors
df = {'name': ['a','b','c','d'], 'value1': [10.1,13.3,9.5,15.1], 'value2': [1.5,2.0,3.5,1.3]}
df = pd.DataFrame(df)
print(df)
colorbar_1 = LinearSegmentedColormap.from_list('colorbar', ['#990000','#FF6666'], N=100)
df[['name','value1']].plot(kind='bar', colormap=colorbar_1 ,width=0.8, ylim=[9,16], fontsize=5)
plt.xticks(df.index,df['name'].values, rotation=90)
plt.ylim([9,16])
plt.gcf().subplots_adjust(bottom=0.15)
plt.tight_layout()
plt.savefig('test.png',dpi=600)
plt.show()
输出
name value1 value2
0 a 10.1 1.5
1 b 13.3 2.0
2 c 9.5 3.5
3 d 15.1 1.3
结果:
所需格式
[
我还生成了第 4 列,其中包含生成的十六进制代码,可用于执行手头的任务。我假设有更简单的方法合并 df['value2'] 但生成十六进制代码可能很方便?
输入
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.colors as colors
df = {'name': ['a','b','c','d'], 'value1': [10.1,13.3,9.5,15.1], 'value2': [1.5,2.0,3.5,1.3]}
df = pd.DataFrame(df)
print(df)
norm = mpl.colors.Normalize(vmin=0, vmax=16, clip=True)
mapper = plt.cm.ScalarMappable(norm=norm, cmap=plt.cm.viridis)
df['hex_code'] = df['value2'].apply(lambda x: colors.to_hex(mapper.to_rgba(x)))
print(df)
输出
name value1 value2
0 a 10.1 1.5
1 b 13.3 2.0
2 c 9.5 3.5
3 d 15.1 1.3
name value1 value2 hex_code
0 a 10.1 1.5 #482374
1 b 13.3 2.0 #472d7b
2 c 9.5 3.5 #3e4989
3 d 15.1 1.3 #481d6f
其中一个问题是,使用 df[['name', 'value1']].plot
会使 pandas 认为您希望数据框中每行有两个条,一个用于 'name',一个用于 'value1' .然后 pandas 感到困惑,因为它无法为 'name' 绘制条形并跳过这些。然后,对于 color=
参数,pandas 现在认为颜色列表中的第一种颜色用于 'name',第二种颜色用于 'value1'。
因此,首先,您需要将其命名为 df['value1'].plot()
。然后,pandas 非常喜欢使用索引作为 x 轴。要将 'name' 作为索引,只需将其设为数据帧的索引即可。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap, LinearSegmentedColormap, Normalize
df = {'name': ['a','b','c','d'], 'value1': [10.1,13.3,9.5,15.1], 'value2': [1.5,2.0,3.5,1.3]}
df = pd.DataFrame(df)
df.set_index('name', inplace=True)
print(df)
colormap_1 = LinearSegmentedColormap.from_list('colorbar', ['#990000','#FF6666'], N=100)
norm = Normalize(vmin=min(df['value2']), vmax=max(df['value2']))
colors = [colormap_1(norm(v)) for v in df['value2']]
df['value1'].plot(kind='bar', color=colors, width=0.8, ylim=[9,16], fontsize=5)
plt.xticks(rotation=90)
plt.ylim([9,16])
plt.tight_layout()
plt.savefig('test.png',dpi=600)
plt.show()
PS:要获得与您的链接图像相似的内容(因此不使用 'value2'),您可以尝试:
# same dataframe as before, with 'name' as index
ymin = 9
ymax = 16
barplot = df['value1'].plot(kind='bar', width=0.8, ylim=[ymin, ymax], fontsize=5)
plt.xticks(rotation=90)
gradient = np.linspace(1,0,256).reshape(256,1)
for bar in barplot.containers[0]:
bar.set_facecolor("none")
x, y = bar.get_xy()
w, h = bar.get_width(), bar.get_height()
plt.imshow(gradient, extent=[x, x + w, y + ymin, y + h], aspect="auto", cmap='bone')
plt.imshow(gradient, extent=[*plt.xlim(), *plt.ylim()] ,aspect="auto", cmap='copper_r', zorder=-1)
plt.tight_layout()
#plt.savefig('test.png',dpi=600)
plt.show()