Mac*_*cer 6 python data-visualization matplotlib pyqtgraph
如何使用matplotlib或pyqtgraph绘制如下图:

线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)
Run Code Online (Sandbox Code Playgroud)
我想到的一个想法是将线的每个部分作为独立线,并在更改缩放级别时重新计算它的位置,但它太复杂和缓慢.
如果有任何简单的方法使用matplotlib或pyqtgraph绘制我想要的东西?任何建议将不胜感激!
如果您可以拥有每条独立的线路,则可以使用该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()
Run Code Online (Sandbox Code Playgroud)
在这里,我将中心线视为参考(因此为负y1width),但可以采用不同的方式。结果是:
如果线条“复杂”,最终在某个点相交,则interpolate=True必须使用关键字参数正确填充交叉区域。另一个可能对您的用例有用的有趣论点是where, 调节区域,例如,where=y1 < 0。有关更多信息,您可以查看文档。
解决问题的一种方法是使用填充多边形、一些线性代数和一些微积分。x主要思想是沿着您的和坐标以及沿着移动坐标绘制多边形y以闭合并填充多边形。
这是代码:
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)
Run Code Online (Sandbox Code Playgroud)
计算如何偏移每个数据点的第一步是计算离散导数dy / dx。我喜欢在 Python 中使用复杂的符号来处理向量,即A = 1 - 1j. 这使得一些数学运算变得更容易。
下一步是记住导数给出了曲线的切线,并且从线性代数中,切线的法线是n=-dy_dx + 1j,使用复数表示法。
确定偏移坐标的最后一步是确保法线向量具有统一的大小n_norm = n / abs(n)并乘以所需的多边形宽度。
现在我们已经有了多边形中点的所有坐标,剩下的就非常简单了。使用patches.Polygon并将它们添加到绘图中。
此代码还允许您定义是否希望补丁位于路线之上或之下。只需给出宽度的正值或负值即可。如果要根据缩放级别和/或分辨率更改多边形的宽度,请调整参数scale。它还使您可以自由地向补丁添加其他参数,例如填充图案、透明度等。