2016-06-10 115 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

相關問題