Matplotlib fill_between带有`where`参数的边缘效果 [英] Matplotlib fill_between edge effect with `where` argument

查看:104
本文介绍了Matplotlib fill_between带有`where`参数的边缘效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想绘制两条颜色不同的曲线之间的区域,而不管其中一条线是正还是负.当曲线符号变化时,我得到了区域非连续着色的边缘效果.设置 interpolate = True 并没有真正的帮助.边缘效果与分辨率有关(在下面的基本示例中自动粗糙) - 增强它并不是我真正想要的.有没有更好的解决方案来平滑过渡?谢谢.

I want to plot the region between two curves with different colors whether one of the line is positive or negative. I got edge effect with non-continuous coloring of the region when the curve changes of sign. Setting interpolate=True does not really help. The edge effect is related to the resolution (voluntarily coarse in the basic example below) - enhancing it is not really what I want. Any better solution to make smooth transitions? Thanks.

import matplotlib.pyplot as plt
import numpy

plt.figure()
x=numpy.arange(0.,1.05,0.05)
y1=numpy.sin(2*numpy.pi*x)
y2=y1+0.2
y1positive=y1>0
y1negative=y1<=0
plt.plot(x,y1,'r',label='y1')
plt.plot(x,y2,'g',label='y2')
plt.plot(x,x*0,'--k')
plt.fill_between(x,y2,y1,where=y1positive,color='green',alpha=0.5)
plt.fill_between(x,y2,y1,where=y1negative,color='red',alpha=0.5,interpolate=True)
plt.legend()

http://i.stack.imgur.com/9Q9Ff.png

** EDIT ** 根据 pyHazard 的回答正确解决了上述问题,但我仍然遇到困难:

** EDIT ** based on pyHazard's answer which is properly addressing the problem above, but I still encounter difficulties:

修订案例(见代码)-如果两条求和曲线之间的区域具有相同的符号,我需要填充它们之间的区域,否则它们之间的区域为零.当 where = 条件改变时,填充区域必须是连续的.包括很小的余量确实有帮助,但不能完全解决问题(填充的表面仍被打断).真正需要的是 fill_between ,其中 y1 = 0 ,这是一个没有宽度的条件...然后,我只需要一种条件 wherey1-eta< = 0< = y1 + eta ,但是我现在被愚蠢地封锁了.任何想法使填充区域完全连续?谢谢!

Revised case (see code) - I need to fill the area between two summed curves if they have the same sign, and between one of them and zero otherwize. The filled area must be continuous when the where= condition changes. Including a tiny margin indeed helps, but does not totally resolve the problem (filled surface still interrupted). What is needed there is really a fill_between where y1=0, which is a condition with no width... I would then just need a kind of condition where y1-eta<=0<=y1+eta but I am foolishly blocked there now. Any idea to make the filled area totally continuous? Thanks!

plt.figure()
x=numpy.arange(0.,3.05,0.05)
y1=numpy.sin(2*numpy.pi*x)
y2=[2.]*len(y1)
y3=[-2.]*len(y1)

eta=1e-6
y1positive=y1+eta>=0
y1negative=y1-eta<=0

plt.plot(x,x*0,'--k')
plt.plot(x,y1,'.-k',label='y1')
plt.plot(x,y2,'.-g',label='y2')
plt.plot(x,y3,'.-r',label='y3')

plt.fill_between(x,y2+y1,y1,where=y1positive,color='green',alpha=0.5,linewidth=0)
plt.fill_between(x,y2,0,where=y1negative,color='green',alpha=0.5,linewidth=0)
plt.fill_between(x,y3+y1,y1,where=y1negative,color='red',alpha=0.5,linewidth=0) 
plt.fill_between(x,y3,0,where=y1positive,color='red',alpha=0.5,linewidth=0) 

plt.legend()

为了更清楚,这里是原始图(上面的代码中带有 eta=0.).那里一切都很好,除了绿色和红色区域的垂直中断.正弦曲线和零之间的空白区域很好.有问题的垂直中断来自填充区域的定义:如果它们具有相同的符号,则在正弦曲线和水平曲线之间,或者如果正弦曲线和水平曲线具有相反的符号,则在水平曲线和零之间.所以填充区域的条件有一个转换,空白的垂直区域是不受欢迎的边缘效果......

To make it clearer, here is the original plot (with eta=0. in the code above). Everything is fine there, except those vertical interruptions in the green and red areas. The blank areas between the sine curve and zero are fine. The problematic vertical interruptions come from the definition of the filled areas: between the sine and the horizontal curve if they have the same sign, or between the horizontal curve and zero if the sine and the horizontal curve have opposite signs. So there is a switch in the conditions for filled areas, the blank vertical zones are the undesirable edge effects...

* 最终编辑 * [带解决方案]

因为我在 fill_between 中找不到解决方案,一个解决方案(基于 pyHazard 的回答)是重新计算填充区域的上限和下限,以确保它们连续(不再有 swith在 fill_between 条件下).

Because I cannot find a solution within fill_between, one solution (based on pyHazard's answer) is to recalculate the upper and lower limit of the filled areas to make sure to have them continuous (no more swith in fill_between condition).

plt.figure()
x=numpy.arange(0.,3.05,0.05)
y1=numpy.sin(2*numpy.pi*x)
y2=[2.]*len(y1)
y3=[-2.]*len(y1)

y1positive=y1>=0
y1negative=y1<=0

plt.plot(x,x*0,'--k')
plt.plot(x,y1,'.-k',label='y1')
plt.plot(x,y2,'.-g',label='y2')
plt.plot(x,y3,'.-r',label='y3')

#Solution: recalculate the upper and lower limit of filled areas
#  to have each of them as one continuous line
y0=[0.]*len(y1)
y1pos=numpy.amax(numpy.vstack((y1,y0)),axis=0.)
y1neg=numpy.amin(numpy.vstack((y1,y0)),axis=0.)
y21=y2+y1pos
y31=y3+y1neg

plt.fill_between(x,y21,y1pos,color='green',alpha=0.5,linewidth=0)
plt.fill_between(x,y31,y1neg,color='red',alpha=0.5,linewidth=0) 

plt.legend()

推荐答案

只要您只关心一行或另一行,我建议查看您的比较.以下产生了一个更令人愉悦的情节.(请注意,更改了绘图样式以使数据点清晰可见.)

As long as you are only concerned with one line or the other I suggest looking at your comparison. The following produces a more pleasing plot. (Note the plotting style was changed to make the data points clear.)

如果您希望负侧的所有 AREA 为红色,正侧为绿色,则需要向位于轴上的系列添加额外的数据点.

If you had intended all of the AREA on the negative side to be red and positive side green you will need to add additional data-points to the series that that lie on the axis.

import matplotlib.pyplot as plt
import numpy

plt.figure()
x=numpy.arange(0.,1.05,0.05)
y1=numpy.sin(2*numpy.pi*x)
y2=y1+0.2

eta=1e-6
y1positive=(y1+eta)>=0
y1negative=(y1-eta)<=0

plt.plot(x,y1,'-r',label='y1')
plt.plot(x,y2,'-g',label='y2')
plt.plot(x,x*0,'--k')
plt.fill_between(x,y2,y1,where=y1positive,color='green',alpha=0.5,interpolate=False)
plt.fill_between(x,y2,y1,where=y1negative,color='red',alpha=0.5,interpolate=False)
plt.legend()
plt.show()

** 编辑 ** 我还不能发表评论,所以我把这个添加到编辑中.我是论坛领域的新手,所以不确定这是否被认为是适当的礼节.

** EDIT ** I cannot yet comment so I'm adding this to an edit. I'm new to the forum scene so I'm not sure if this is considered proper etiquette.

我不确定我是否了解修订后的情况.你只是想用红色和绿色填充白色区域吗?如果是这样,您可能不需要额外的条件,只需要以最简单的方式填充它们,如下所示.

I'm not sure I understand the revised situation. Are you simply trying to fill the white areas in with red and green? If so you probably don't need the extra conditionals and just need to to the fill between in the simplest way as shown below.

plt.figure()
x=numpy.arange(0.,3.05,0.05)
y1=numpy.sin(2*numpy.pi*x)
y2=[ 2.]*len(y1)
y3=[-2.]*len(y1)

y21 = numpy.amax(numpy.vstack((y2,y2+y1)), axis=0)
y31 = numpy.amin(numpy.vstack((y3,y3+y1)), axis=0)

plt.plot(x,x*0,'--k')
plt.fill_between(x,y21,y1,color='green',alpha=0.5,linewidth=0)
plt.fill_between(x,y31,y1,color='red',alpha=0.5,linewidth=0) 

plt.show()

这篇关于Matplotlib fill_between带有`where`参数的边缘效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆