Python Matplotlib中基于颜色条的图例

3
在下面的图形中,我想为日历图添加一个图例。该日历图是使用ax.plot(...,label ='a')制作的,并在52x7网格(52周,每周7天)中绘制矩形。
图例目前是使用以下方式创建的:
plt.gca().legend(loc="upper right")

我该如何将图例更改为类似于色条的形式?另外,色条应放置在绘图底部。 编辑: 上传了代码和数据以便重现,链接如下: https://www.dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0

enter image description here


1
你能提供一个最小化可复现的示例吗?这样我们就可以确切地了解你正在做什么并进行实验。 - Bakuriu
感谢@Bakuriu,代码有点长,所以我已经在这里上传了它:https://www.dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0 - user308827
1
这看起来很棒,我想运行代码,但是数据不再通过Dropbox提供。有人能提供'94.DGN'数据集吗? - rul30
2个回答

7

旁注 - 存在的漏洞

你放在 Dropbox 上的代码“开箱即用”并不起作用。特别是,你试图在两个地方将 datetime.timedelta 除以 numpy.timedelta64,结果失败了。

你自己进行了标准化和颜色映射(根据你的标准化值的 int() 转换调用到 color_list)。你从中减去了 1,但实际上不需要这样做——你已经使用 int() 对值进行了向下取整。这样做的结果是,你可能会得到一个索引为 -1 的值,这意味着你的非常小的值被错误地映射到最大值的颜色上。如果绘制列 'BIOM',这一点最为明显。

我通过给你要除以的值的总范围添加了一个微小的值 (0.00001) 来解决这个问题。这是一个 hack,我不确定这种映射方法是否是 matplotlib 的最佳使用方式,但这是完全不同的问题。

适应你的代码的解决方案

随着这些错误的修复,并在所有现有subplot下方添加一个最后的suplot(即在对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上进行了测试(考虑到print语句的语法,我假设你正在使用Python 2.x)。

最终的代码可以直接与你的数据文件一起使用,在此处的gist中

你将得到

Picture of output axes (NMN and BIOM)

它是如何工作的?

它创建了一个ScalarMappable对象,供matplotlib用于将值映射到颜色上。它将数组设置为基于您正在处理的列中的所有值。然后使用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

这样,你就可以保持你的代码DRY,并且只需更改一次颜色即可。

布局(回答评论)

对于审美理念来说,颜色条可能有点大(当然高)。 有几种可能的选项。 我将指出两个:

  1. “正确”的方法可能是使用 Gridspec

  2. 您可以使用现有的方法,但增加行数,使颜色条仍在一行中,而其他元素跨度比当前跨度更多的行。

我已经使用了9行,额外的一列(这样月份标签就不会丢失),并将色条放在底部行,比主图少跨越2列。我还使用了tight_layoutw_pad=0.0以避免标签冲突。您可以调整此设置以获得所需的精确尺寸。新代码在这里。
这将给出:

enter image description here:


谢谢 @Richard!这太棒了。非常感谢你修复错误。有没有办法减小色条的高度?我尝试了缩小=.5,垫=.2,但好像不起作用... - user308827
@user308827,请查看答案更新-享受与格式化的玩耍 :) - J Richard Snape
没问题,很高兴能帮忙。期待赏金的到来 :) - J Richard Snape

1
在matplotlib.colorbar中有相应的函数可以实现这一功能。根据您提供的示例代码,我可以给您提供更好的答案,但您需要使用类似以下的代码: myColorbar = matplotlib.colorbar.ColorbarBase(myAxes, cmap=myColorMap, norm=myNorm, orientation='vertical')

谢谢,代码有点长,所以我已经在这里上传了它: dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0 - user308827

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接