在 matplotlib 中定义颜色图的中点
我想设置颜色图的中间点,即我的数据从-5到10,我希望零作为中间点。我认为做到这一点的方法是通过子类化标准化并使用规范,但我没有找到任何示例,而且我不清楚,我到底要实现什么?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我想设置颜色图的中间点,即我的数据从-5到10,我希望零作为中间点。我认为做到这一点的方法是通过子类化标准化并使用规范,但我没有找到任何示例,而且我不清楚,我到底要实现什么?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(11)
我知道这已经晚了,但我刚刚经历了这个过程,并提出了一个解决方案,该解决方案可能不如子类规范化强大,但简单得多。我认为在这里与后代分享是件好事。
函数
示例 示例
结果:
I know this is late to the game, but I just went through this process and came up with a solution that perhaps less robust than subclassing normalize, but much simpler. I thought it'd be good to share it here for posterity.
The function
An example
Results of the example:
请注意,在 matplotlib 版本 3.2+ 中 TwoSlopeNorm 类。我认为它涵盖了您的用例。
它可以这样使用:
在 matplotlib 3.1 中,该类被称为 DivergingNorm 。
Note that in matplotlib version 3.2+ the TwoSlopeNorm class was added. I think it covers your use case.
It can be used like this:
In matplotlib 3.1 the class was called DivergingNorm.
最简单的方法是使用
imshow
的vmin
和vmax
参数(假设您正在处理图像数据),而不是子类化matplotlib .colors.Normalize
。例如
It's easiest to just use the
vmin
andvmax
arguments toimshow
(assuming you're working with image data) rather than subclassingmatplotlib.colors.Normalize
.E.g.
这是归一化归一化的解决方案。使用它的
类如下:
Here is a solution subclassing Normalize. To use it
Here is the Class:
在这里,我创建了
Normalize
的子类,后面是一个最小的示例。结果:
仅包含正数据的同一示例
vals = np.array([[1., 3], [6, 10]])
属性:
vmin
大于midpoint
似乎也能正常工作(但没有测试所有边缘情况)。此解决方案的灵感来自此页面中的同名类
Here I create a subclass of
Normalize
followed by a minimal example.Result:
The same example with only positive data
vals = np.array([[1., 3], [6, 10]])
Properties:
vmin
is bigger thanmidpoint
(did not test all the edge cases though).This solution is inspired by a class with the same name from this page
不确定您是否仍在寻找答案。对我来说,尝试子类化
Normalize
并不成功。因此,我专注于手动创建一个新的数据集、刻度和刻度标签,以获得我认为您想要的效果。我在 matplotlib 中发现了
scale
模块,该模块有一个用于通过“syslog”规则转换线图的类,因此我使用它来转换数据。然后我缩放数据,使其从 0 变为 1(Normalize
通常执行的操作),但我对正数的缩放方式与负数的缩放方式不同。这是因为你的 vmax 和 vmin 可能不一样,所以 0.5 -> 1 可能覆盖比 0.5 更大的正范围 -> 0.5。 0,负数范围。对我来说,创建一个例程来计算刻度值和标签值更容易。下面是代码和示例图。
随意调整“常量”(例如
VMAX
)位于脚本顶部,以确认其运行良好。Not sure if you are still looking for an answer. For me, trying to subclass
Normalize
was unsuccessful. So I focused on manually creating a new data set, ticks and tick-labels to get the effect I think you are aiming for.I found the
scale
module in matplotlib that has a class used to transform line plots by the 'syslog' rules, so I use that to transform the data. Then I scale the data so that it goes from 0 to 1 (whatNormalize
usually does), but I scale the positive numbers differently from the negative numbers. This is because your vmax and vmin might not be the same, so .5 -> 1 might cover a larger positive range than .5 -> 0, the negative range does. It was easier for me to create a routine to calculate the tick and label values.Below is the code and an example figure.
Feel free to adjust the "constants" (eg
VMAX
) at the top of the script to confirm that it behaves well.对于 matplotlib 版本 3.4 或更高版本,也许最简单的解决方案是使用新的 CenteredNorm。
使用 CenteredNorm 和 发散颜色图之一的示例:
很简单,
CenteredNorm
是对称的,因此如果数据从 -5 到 10,颜色图将从 -10 拉伸到 10。如果您希望在中心的两侧使用不同的映射,以便颜色图范围从 -5 到 10,请使用 TwoSlopeNorm 如 @macKaiver 的答案中所述。
With matplotlib version 3.4 or later, the perhaps simplest solution is to use the new CenteredNorm.
Example using CenteredNorm and one of the diverging colormaps:
Being simple,
CenteredNorm
is symmetrical, so that if the data goes from -5 to 10, the colormap will be stretched from -10 to 10.If you want a different mapping on either side of the center, so that the colormap ranges from -5 to 10, use the TwoSlopeNorm as described in @macKaiver's answer.
我使用了 Paul H 的出色答案,但遇到了一个问题,因为我的一些数据范围从负到正,而其他数据集范围从 0 到正或从负到 0;无论哪种情况,我都希望 0 被着色为白色(我正在使用的颜色图的中点)。在现有实现中,如果您的
中点
值等于 1 或 0,则原始映射不会被覆盖。您可以在下图中看到:进行了编辑:编辑: 当某些我的数据范围从较小的正值到较大的正值,其中非常低的值被涂成红色而不是白色。我通过在上面的代码中添加行
Edit #2
来修复它。I was using the excellent answer from Paul H, but ran into an issue because some of my data ranged from negative to positive, while other sets ranged from 0 to positive or from negative to 0; in either case I wanted 0 to be coloured as white (the midpoint of the colormap I'm using). With the existing implementation, if your
midpoint
value is equal to 1 or 0, the original mappings were not being overwritten. You can see that in the following picture:The 3rd column looks correct, but the dark blue area in the 2nd column and the dark red area in the remaining columns are all supposed to be white (their data values are in fact 0). Using my fix gives me:
My function is essentially the same as that from Paul H, with my edits at the start of the
for
loop:EDIT: I ran into a similar issue yet again when some of my data ranged from a small positive value to a larger positive value, where the very low values were being coloured red instead of white. I fixed it by adding line
Edit #2
in the code above.我的解决方案涉及创建截断的颜色图,其中截断限制是根据数据中的最小值和最大值确定的。
其中:
注意我的代码是专门为处理以下情况而编写的:(a)
vmin
和vmax
具有相反的符号,或 (b) 以下情况之一它们是0
。如果有人愿意,可以直接将两者都为负面或正面的情况包括在内。说明用法:
以情况 (a) 为例,其中
vmin < 0 和 vmax > 0
:情况 (b) 的示例,其中
vmin < 0
和vmax == 0
:My solution involves creating a truncated colormap, where the truncation limits are determined from the mininimum and maximum values in your data.
where:
Note my code is written specifically to handle the cases where (a)
vmin
andvmax
have opposite signs, or (b) one of them is0
. It would be straightforward to include the cases where both are negative or positive, if one wanted.To illustrate the usage:
Example of case (a), with
vmin < 0
andvmax > 0
:Example of case (b), with
vmin < 0
andvmax == 0
:如果您不介意计算出 vmin、vmax 和零之间的比率,这是一个从蓝色到白色到红色的非常基本的线性映射,它根据比率
z
设置白色:cdict格式相当简单:行是创建的渐变中的点:第一个条目是 x 值(沿渐变从 0 到 1 的比率),第二个条目是前一段的结束值,第三个条目是是下一段的起始值 - 如果你想要平滑梯度,后两者总是相同的。 请参阅文档了解更多详细信息。
If you don't mind working out the ratio between vmin, vmax, and zero, this is a pretty basic linear map from blue to white to red, that sets white according to the ratio
z
:The cdict format is fairly simple: the rows are points in the gradient that gets created: the first entry is the x-value (the ratio along the gradient from 0 to 1), the second is the end value for the previous segment, and the third is the start value for the next segment - if you want smooth gradients, the latter two are always the same. See the docs for more detail.
我遇到了类似的问题,但我希望最高值是全红色,并切断蓝色的低值,使其看起来基本上就像颜色条的底部被切掉一样。这对我有用(包括可选的透明度):
I had a similar problem, but I wanted the highest value to be full red and cut off low values of blue, making it look essentially like the bottom of the colorbar was chopped off. This worked for me (includes optional transparency):