2016-06-10 116 views
6

如何使用matplotlib或pyqtgraph平局情节是这样的: two dirrections widths line如何绘制“两个方向宽度线”在matplotlib

AB线是两方向的街道,绿色部分表示从点A到点方向B,红色部分代表B到A,每个部分的宽度代表交通量。 宽度是按点测量的,不会在不同的缩放级别或dpi设置下更改

这只是一个例子,实际上我有街头巷尾。这种情节在很多流量软件中很常见。我试图用matplotlib的patheffect但结果是沮丧:

from matplotlib import pyplot as plt 
import matplotlib.patheffects as path_effects 

x=[0,1,2,3] 
y=[1,0,0,-1] 
ab_width=20 
ba_width=30 

fig, axes= plt.subplots(1,1) 
center_line, = axes.plot(x,y,color='k',linewidth=2) 

center_line.set_path_effects(
[path_effects.SimpleLineShadow(offset=(0, -ab_width/2),shadow_color='g', alpha=1, linewidth=ab_width), 
path_effects.SimpleLineShadow(offset=(0, ba_width/2), shadow_color='r', alpha=1, linewidth=ba_width), 
path_effects.SimpleLineShadow(offset=(0, -ab_width), shadow_color='k', alpha=1, linewidth=2), 
path_effects.SimpleLineShadow(offset=(0, ba_width), shadow_color='k', alpha=1, linewidth=2), 
path_effects.Normal()]) 

axes.set_xlim(-1,4) 
axes.set_ylim(-1.5,1.5) 

enter image description here

一个想法来找我是走线的每个部分作为独立的线,并重新计算它的位置改变缩放级别时,但它太复杂和缓慢。

如果有任何简单的方法使用matplotlib或pyqtgraph绘制我想要的东西?任何建议将不胜感激!

+1

您的数字不工作 – Bart

+0

对不起,我修理它@巴特 – Macer

+0

不,仍然不工作..为什么不使用图像上传由stackoverflow提供? – Bart

回答

4

如果您可以拥有每条独立的线路,则可以使用fill_between功能轻松完成此操作。

from matplotlib import pyplot as plt 
import numpy as np 

x=np.array([0,1,2,3]) 
y=np.array([1,0,0,-1]) 

y1width=-1 
y2width=3 
y1 = y + y1width 
y2 = y + y2width 

fig = plt.figure() 
ax = fig.add_subplot(111) 

plt.plot(x,y, 'k', x,y1, 'k',x,y2, 'k',linewidth=2) 
ax.fill_between(x, y1, y, color='g') 
ax.fill_between(x, y2, y, color='r') 

plt.xlim(-1,4) 
plt.ylim(-3,6) 
plt.show() 

在这里,我认为中心线作为基准(因此负y1width),但也可以做不同。其结果则是:

<code>fill_between</code> result.

如果行“复杂”,最终在某一点相交,然后在关键字参数interpolate=True必须被用于正确填写交叉区域。另一个可能对您的用例有用的有趣参数是where,以调节区域,例如where=y1 < 0。欲了解更多信息,你可以查看documentation

+0

感谢您的回答,但您可能不完全了解我的需求。宽度应该按点测量,并且不会在不同的缩放级别下更改。它被用于交互式应用程序中,用户经常需要放大和缩小并平移以观察不同的行。在你的回答中,缩放后宽度不固定。终点也有点不同。 – Macer

+0

的确,我没有得到“恒定宽度”的部分。为此,您需要捕捉缩放事件,为阴影设置合适的比例(通过增加或减少原始宽度)并重新绘制。按照[这个要点](https://gist.github.com/tacaswell/3144287)看到相关的东西(相关,不完全是你在找什么)。至于这个'fill_between'方法无法再帮助的结局。 – rll

3

解决您的问题的一种方法是使用填充多边形,一些线性代数和一些微积分。主要想法是沿着您的xy坐标绘制多边形,并沿着移动的坐标绘制多边形以关闭和填充多边形。

这是我的结果:Filled polygons along path

这里是代码:

from __future__ import division 
import numpy 
from matplotlib import pyplot, patches 


def road(x, y, w, scale=0.005, **kwargs): 
    # Makes sure input coordinates are arrays. 
    x, y = numpy.asarray(x, dtype=float), numpy.asarray(y, dtype=float) 
    # Calculate derivative. 
    dx = x[2:] - x[:-2] 
    dy = y[2:] - y[:-2] 
    dy_dx = numpy.concatenate([ 
     [(y[1] - y[0])/(x[1] - x[0])], 
     dy/dx, 
     [(y[-1] - y[-2])/(x[-1] - x[-2])] 
    ]) 
    # Offsets the input coordinates according to the local derivative. 
    offset = -dy_dx + 1j 
    offset = w * scale * offset/abs(offset) 
    y_offset = y + w * scale 
    # 
    AB = zip(
     numpy.concatenate([x + offset.real, x[::-1]]), 
     numpy.concatenate([y + offset.imag, y[::-1]]), 
    ) 
    p = patches.Polygon(AB, **kwargs) 

    # Returns polygon. 
    return p 


if __name__ == '__main__': 
    # Some plot initializations 
    pyplot.close('all') 
    pyplot.ion() 

    # This is the list of coordinates of each point 
    x = [0, 1, 2, 3, 4] 
    y = [1, 0, 0, -1, 0] 

    # Creates figure and axes. 
    fig, ax = pyplot.subplots(1,1) 
    ax.axis('equal') 
    center_line, = ax.plot(x, y, color='k', linewidth=2) 

    AB = road(x, y, 20, color='g') 
    BA = road(x, y, -30, color='r') 
    ax.add_patch(AB) 
    ax.add_patch(BA) 

在计算如何抵消每个数据点的第一个步骤是通过计算离散导dy/dx。我喜欢用复杂的符号来处理Python中的矢量,即A = 1 - 1j。这使得一些数学运算更容易。

下一步是要记住,衍生物给出的切线曲线和从线性代数的是,垂直于切线是n=-dy_dx + 1j,使用复杂的表示法。

确定偏移坐标的最后一步是确保法向矢量的单位尺寸为n_norm = n/abs(n)并乘以所需的多边形宽度。

现在我们已经有了多边形中所有点的坐标,其余的都很简单。使用patches.Polygon并将它们添加到图中。

这段代码还允许你定义你想要的路径上还是下面的路径。只需给出正面或负面的宽度值。如果要根据缩放级别和/或分辨率更改多边形的宽度,请调整参数scale。它也给你自由添加额外的参数补丁,如填充图案,透明度等

+0

优秀!但仍然无法解决“缩放后重量不变”的问题。也许没有指令性的方式来使用matplotlib来解决问题。我需要捕捉缩放事件,重新计算并重新绘制它。 – Macer

相关问题