简体   繁体   English

python matplotlib中基于Colorbar的图例

[英]Colorbar based legend in python matplotlib

In the graphic below, I want to put in a legend for the calendar plot. 在下图中,我想为日历图添加一个图例。 The calendar plot was made using ax.plot(...,label='a') and drawing rectangles in a 52x7 grid (52 weeks, 7 days per week). 使用ax.plot(...,label ='a')绘制日历图,并在52x7网格中绘制矩形(52周,每周7天)。

The legend is currently made using: 该传奇目前使用:

plt.gca().legend(loc="upper right")

How do I correct this legend to something more like a colorbar? 如何将此图例更正为更像颜色条的内容? Also, the colorbar should be placed at the bottom of the plot. 此外,颜色条应放在图的底部。

EDIT: Uploaded code and data for reproducing this here: https://www.dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0 编辑:上传的代码和数据在这里复制: https//www.dropbox.com/sh/8xgyxybev3441go/AACKDiNFBqpsP1ZttsZLqIC4a?dl=0

在此输入图像描述

Aside - existing bugs 除了 - 现有的错误

The code you put on the dropbox doesn't work "out of the box". 您放在Dropbox上的代码无法“开箱即用”。 In particular - you're trying to divide a datetime.timedelta by a numpy.timedelta64 in two places and that fails. 特别是 - 你试图在两个地方用numpy.timedelta64划分datetime.timedelta并且失败了。

You do your own normalisation and colour mapping (calling into color_list based on an int() conversion of your normalised value). 您可以进行自己的规范化和颜色映射(根据规范化值的int()转换调用color_list )。 You subtract 1 from this and you don't need to - you already floor the value by using int() . 你从中减去1并且你不需要 - 你已经使用int()对值进行了底层。 The result of doing this is that you can get an index of -1 which means your very smallest values are incorrectly mapped to the colour for the maximum value. 执行此操作的结果是您可以获得-1的索引,这意味着您的最小值被错误地映射到最大值的颜色。 This is most obvious if you plot column 'BIOM' . 如果您绘制列'BIOM'这是最明显'BIOM'

I've hacked this by adding a tiny value ( 0.00001 ) to the total range of the values that you divide by. 我通过在你除以的值的总范围中添加一个微小的值( 0.00001 )来攻击它。 It's a hack - I'm not sure that this method of mapping is at all the best use of matplotlib, but that's a different question entirely. 这是一个黑客 - 我不确定这种映射方法是matplotlib的最佳用法,但这完全是一个不同的问题。

Solution adapting your code 解决方案适应您的代码

With those bugs fixed, and adding a last suplot below all the existing ones (ie replacing 3 with 4 on all your calls to subplot2grid() , you can do the following: 修复了这些错误,并在所有现有错误下面添加最后一个suplot(即在所有调用subplot2grid()3替换为4 ,您可以执行以下操作:

Replace your 替换你的

plt.gca().legend(loc="upper right")

with

# 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')

I tested this with two of your columns ( 'NMN' and 'BIOM' ) and on Python 2.7 (I assume you're using Python 2.x given the print statement syntax) 我用你的两个列( 'NMN''BIOM' )和Python 2.7测试了这个(我假设你使用Python 2.x给出了print语句的语法)

The finalised code that works directly with your data file is in a gist here 直接使用您的数据文件的最终代码在这里一个要点

You get 你得到

输出轴(NMN和BIOM)的图片

How does it work? 它是如何工作的?

It creates a ScalarMappable object that matplotlib can use to map values to colors. 它创建了一个ScalarMappable对象,matplotlib可以使用该对象将值映射到颜色。 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() to add the colorbar - passing in the mappable object so that the labels are correct. 然后使用Figure.colorbar()添加Figure.colorbar() - 传入可映射对象,以便标签正确。 I've added boundaries so that the minimum value is shown explicitly - you can omit that if you want matplotlib to sort that out for itself. 我添加了边界,以便显式显示最小值 - 如果您希望matplotlib为其自身排序,则可以省略它。

PS I've set the colormap to palettable.colorbrewer.sequential.BuPu_9.mpl_colormap , matching your get_colors() function which gets these colours as a 9 member list. PS我已经将colormap设置为palettable.colorbrewer.sequential.BuPu_9.mpl_colormap ,匹配你的get_colors()函数,该函数将这些颜色作为9个成员列表。 I strongly recommend importing the colormap you want to use as a nice name to make the use of mpl_colors and mpl_colormap more easy to understand eg 我强烈建议您输入要用作好名称的色彩图,以便更容易理解mpl_colors和mpl_colormap的使用,例如

import palettable.colorbrewer.sequential.BuPu_9 as color_scale

Then access it as 然后访问它

color_scale.mpl_colormap

That way, you can keep your code DRY and change the colors with only one change. 这样,您可以保持代码干燥并仅使用一次更改来更改颜色。

Layout (in response to comments) 布局(回应评论)

The colorbar may be a little big (certainly tall) for aesthetic ideal. 对于美学理想,色条可能有点大(当然很高)。 There are a few possible options to do that. 有几种可能的选择。 I'll point you to two: 我会指出你两个:

  1. The "right" way to do it is probably to use a Gridspec “正确”的方式可能是使用Gridspec

  2. You could use your existing approach, but increase the number of rows and have the colorbar still in one row, while the other elements span more rows than they do currently. 您可以使用现有方法,但增加行数并使颜色栏仍然在一行中,而其他元素跨越的行数多于当前行。

I've implemented that with 9 rows, an extra column (so that the month labels don't get lost) and the colorbar on the bottom row, spanning 2 less columns than the main figure. 我已经实现了9行,一个额外的列(以便月份标签不会丢失)和底行的颜色栏,比主图少两列。 I've also used tight_layout with w_pad=0.0 to avoid label clashes. 我还用tight_layoutw_pad=0.0 ,以避免标签冲突。 You can play with this to get your exact preferred size. 您可以使用它来获得您确切的首选大小。 New code here. 这里有新代码。

This gives: 这给出了:

在此输入图像描述 :

There are functions to do this in matplotlib.colorbar. 在matplotlib.colorbar中有一些函数可以执行此操作。 With some specific code from your example, I could give you a better answer, but you'll use something like: 使用您的示例中的一些特定代码,我可以给您一个更好的答案,但您将使用以下内容:

myColorbar = matplotlib.colorbar.ColorbarBase(myAxes, cmap=myColorMap, norm=myNorm, orientation='vertical')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM