python matplotlib 中基于颜色条的图例
Colorbar based legend in python matplotlib
在下图中,我想为日历图添加图例。日历图是使用 ax.plot(...,label='a') 绘制的,并在 52x7 网格(52 周,每周 7 天)中绘制矩形。
图例目前使用:
plt.gca().legend(loc="upper right")
如何将此图例更正为更像颜色条的内容?另外,颜色条应该放在图的底部。
编辑:
上传代码和数据以在此处重现此内容:
https://www.dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0
matplotlib.colorbar 中有执行此操作的函数。使用您示例中的一些特定代码,我可以为您提供更好的答案,但您将使用类似:
myColorbar = matplotlib.colorbar.ColorbarBase(myAxes, cmap=myColorMap,
norm=myNorm,
orientation='vertical')
撇开 - 存在的错误
您放入保管箱的代码“开箱即用”。特别是 - 你试图在两个地方将 datetime.timedelta
除以 numpy.timedelta64
但失败了。
您进行自己的标准化和颜色映射(根据标准化值的 int()
转换调用 color_list
)。您从中减去 1
而您不需要 - 您已经使用 int()
降低了该值。这样做的结果是您可以获得 -1
的索引,这意味着您的最小值被错误地映射到最大值的颜色。如果绘制 'BIOM'
.
列,这一点最为明显
我通过将一个小值 (0.00001
) 添加到您除以的值的总范围来解决这个问题。这是一个 hack - 我不确定这种映射方法是否是 matplotlib 的最佳用途,但这完全是一个不同的问题。
调整您的代码的解决方案
修复了这些错误,并在所有现有错误下方添加了最后一个补充情节(即在您对 subplot2grid()
的所有调用中将 3
替换为 4
,您可以执行以下操作:
替换你的
plt.gca().legend(loc="upper right")
和
# plot an overall colorbar type legend
# Grab the new axes object to plot the colorbar on
ax_colorbar = plt.subplot2grid((4,num_yrs), (3,0),rowspan=1,colspan=num_yrs)
mappableObject = matplotlib.cm.ScalarMappable(cmap = palettable.colorbrewer.sequential.BuPu_9.mpl_colormap)
mappableObject.set_array(numpy.array(df[col_name]))
col_bar = fig.colorbar(mappableObject, cax = ax_colorbar, orientation = 'horizontal', boundaries = numpy.arange(min_val,max_val,(max_val-min_val)/10))
# You can change the boundaries kwarg to either make the scale look less boxy (increase 10)
# or to get different values on the tick marks, or even omit it altogether to let
col_bar.set_label(col_name)
ax_colorbar.set_title(col_name + ' color mapping')
我用你的两个列('NMN'
和 'BIOM'
)和 Python 2.7(我假设你使用的是 Python 2.x 给定 print
语句语法)
直接与您的数据文件一起使用的最终代码是in a gist here
你得到
它是如何工作的?
它创建了一个 ScalarMappable
object that matplotlib can use to map values to colors. It set the array to base this map on to all the values in the column you are dealing with. It then used Figure.colorbar()
来添加颜色条 - 传入可映射对象以便标签正确。我添加了边界,以便明确显示最小值 - 如果您希望 matplotlib 自行解决,您可以省略它。
P.S. 我已将颜色图设置为 palettable.colorbrewer.sequential.BuPu_9.mpl_colormap
,匹配你的 get_colors()
函数,该函数将这些颜色作为 9 成员列表。我强烈建议导入你想使用的颜色图作为一个好听的名字,使 mpl_colors 和 mpl_colormap 的使用更容易理解,例如
import palettable.colorbrewer.sequential.BuPu_9 as color_scale
然后以
访问它
color_scale.mpl_colormap
这样一来,您就可以保持代码干爽,只需更改一次即可更改颜色。
布局(回复评论)
为了审美理想,颜色条可能有点大(当然高)。有几个可能的选择可以做到这一点。我会指出两个:
“正确”的方法可能是使用 Gridspec
您可以使用现有的方法,但增加行数并使颜色条仍然在一行中,而其他元素比当前跨越更多行。
我已经实现了 9 行,一个额外的列(这样月份标签就不会丢失)和底行的颜色条,比主图少 2 列。我还使用 tight_layout
和 w_pad=0.0
来避免标签冲突。您可以玩这个以获得您喜欢的确切尺寸。 New code here.
这给出:
:
在下图中,我想为日历图添加图例。日历图是使用 ax.plot(...,label='a') 绘制的,并在 52x7 网格(52 周,每周 7 天)中绘制矩形。
图例目前使用:
plt.gca().legend(loc="upper right")
如何将此图例更正为更像颜色条的内容?另外,颜色条应该放在图的底部。
编辑: 上传代码和数据以在此处重现此内容: https://www.dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0
matplotlib.colorbar 中有执行此操作的函数。使用您示例中的一些特定代码,我可以为您提供更好的答案,但您将使用类似:
myColorbar = matplotlib.colorbar.ColorbarBase(myAxes, cmap=myColorMap,
norm=myNorm,
orientation='vertical')
撇开 - 存在的错误
您放入保管箱的代码“开箱即用”。特别是 - 你试图在两个地方将 datetime.timedelta
除以 numpy.timedelta64
但失败了。
您进行自己的标准化和颜色映射(根据标准化值的 int()
转换调用 color_list
)。您从中减去 1
而您不需要 - 您已经使用 int()
降低了该值。这样做的结果是您可以获得 -1
的索引,这意味着您的最小值被错误地映射到最大值的颜色。如果绘制 'BIOM'
.
我通过将一个小值 (0.00001
) 添加到您除以的值的总范围来解决这个问题。这是一个 hack - 我不确定这种映射方法是否是 matplotlib 的最佳用途,但这完全是一个不同的问题。
调整您的代码的解决方案
修复了这些错误,并在所有现有错误下方添加了最后一个补充情节(即在您对 subplot2grid()
的所有调用中将 3
替换为 4
,您可以执行以下操作:
替换你的
plt.gca().legend(loc="upper right")
和
# plot an overall colorbar type legend
# Grab the new axes object to plot the colorbar on
ax_colorbar = plt.subplot2grid((4,num_yrs), (3,0),rowspan=1,colspan=num_yrs)
mappableObject = matplotlib.cm.ScalarMappable(cmap = palettable.colorbrewer.sequential.BuPu_9.mpl_colormap)
mappableObject.set_array(numpy.array(df[col_name]))
col_bar = fig.colorbar(mappableObject, cax = ax_colorbar, orientation = 'horizontal', boundaries = numpy.arange(min_val,max_val,(max_val-min_val)/10))
# You can change the boundaries kwarg to either make the scale look less boxy (increase 10)
# or to get different values on the tick marks, or even omit it altogether to let
col_bar.set_label(col_name)
ax_colorbar.set_title(col_name + ' color mapping')
我用你的两个列('NMN'
和 'BIOM'
)和 Python 2.7(我假设你使用的是 Python 2.x 给定 print
语句语法)
直接与您的数据文件一起使用的最终代码是in a gist here
你得到
它是如何工作的?
它创建了一个 ScalarMappable
object that matplotlib can use to map values to colors. It set the array to base this map on to all the values in the column you are dealing with. It then used Figure.colorbar()
来添加颜色条 - 传入可映射对象以便标签正确。我添加了边界,以便明确显示最小值 - 如果您希望 matplotlib 自行解决,您可以省略它。
P.S. 我已将颜色图设置为 palettable.colorbrewer.sequential.BuPu_9.mpl_colormap
,匹配你的 get_colors()
函数,该函数将这些颜色作为 9 成员列表。我强烈建议导入你想使用的颜色图作为一个好听的名字,使 mpl_colors 和 mpl_colormap 的使用更容易理解,例如
import palettable.colorbrewer.sequential.BuPu_9 as color_scale
然后以
访问它color_scale.mpl_colormap
这样一来,您就可以保持代码干爽,只需更改一次即可更改颜色。
布局(回复评论)
为了审美理想,颜色条可能有点大(当然高)。有几个可能的选择可以做到这一点。我会指出两个:
“正确”的方法可能是使用
Gridspec
您可以使用现有的方法,但增加行数并使颜色条仍然在一行中,而其他元素比当前跨越更多行。
我已经实现了 9 行,一个额外的列(这样月份标签就不会丢失)和底行的颜色条,比主图少 2 列。我还使用 tight_layout
和 w_pad=0.0
来避免标签冲突。您可以玩这个以获得您喜欢的确切尺寸。 New code here.
这给出: