我想画不同颜色的平行线。我想要两条粗细为3的平行线,一条红色的,一条蓝色的,而不是一条粗细为6的红线。任何想法都将不胜感激。
谢谢
即使有了智能偏移(如下所示),在连续点之间具有锐角的视图中仍然存在问题。
智能偏移的缩放视图:

覆盖不同粗细的线:

发布于 2017-02-13 00:55:18
绘制平行线并不是一件容易的事情。使用简单的均匀偏移量当然不会显示预期的结果。下面的左图显示了这一点。
这样一个简单的偏移量可以在matplotlib中生成,如transformation tutorial所示。

Method1
一个更好的解决方案可能是使用右边的想法。为了计算n点的偏移量,我们可以使用n-1st和n+1st点之间的线的法向量,并使用沿着该法向量的相同距离来计算偏移点。
这种方法的优点是,我们在原始线中的点数与在偏移线中的点数相同。缺点是它不是完全准确的,如图所示。
此方法在以下代码中的函数offset中实现。
为了使这对matplotlib图有用,我们需要考虑线宽应该独立于数据单元。线宽通常以点为单位给出,偏移量最好以相同的单位给出,这样例如可以满足问题中的要求(“宽度为3的两条平行线”)。因此,我们的想法是使用ax.transData.transform将坐标从数据转换为显示坐标。点o中的偏移量也可以转换为相同的单位:使用dpi和ppi=72标准,显示坐标中的偏移量为o*dpi/ppi。在应用了显示坐标中的偏移量之后,反变换(ax.transData.inverted().transform)允许反向变换。
现在问题的另一个方面是:如何确保偏移量保持不变,而与图形的缩放和大小无关?最后一点可以通过在每次缩放事件发生时重新计算偏移量来解决。
这是通过这种方法生成的彩虹曲线的样子。

这是生成图像的代码。
import numpy as np
import matplotlib.pyplot as plt
dpi = 100
def offset(x,y, o):
""" Offset coordinates given by array x,y by o """
X = np.c_[x,y].T
m = np.array([[0,-1],[1,0]])
R = np.zeros_like(X)
S = X[:,2:]-X[:,:-2]
R[:,1:-1] = np.dot(m, S)
R[:,0] = np.dot(m, X[:,1]-X[:,0])
R[:,-1] = np.dot(m, X[:,-1]-X[:,-2])
On = R/np.sqrt(R[0,:]**2+R[1,:]**2)*o
Out = On+X
return Out[0,:], Out[1,:]
def offset_curve(ax, x,y, o):
""" Offset array x,y in data coordinates
by o in points """
trans = ax.transData.transform
inv = ax.transData.inverted().transform
X = np.c_[x,y]
Xt = trans(X)
xto, yto = offset(Xt[:,0],Xt[:,1],o*dpi/72. )
Xto = np.c_[xto, yto]
Xo = inv(Xto)
return Xo[:,0], Xo[:,1]
# some single points
y = np.array([1,2,2,3,3,0])
x = np.arange(len(y))
#or try a sinus
x = np.linspace(0,9)
y=np.sin(x)*x/3.
fig, ax=plt.subplots(figsize=(4,2.5), dpi=dpi)
cols = ["#fff40b", "#00e103", "#ff9921", "#3a00ef", "#ff2121", "#af00e7"]
lw = 2.
lines = []
for i in range(len(cols)):
l, = plt.plot(x,y, lw=lw, color=cols[i])
lines.append(l)
def plot_rainbow(event=None):
xr = range(6); yr = range(6);
xr[0],yr[0] = offset_curve(ax, x,y, lw/2.)
xr[1],yr[1] = offset_curve(ax, x,y, -lw/2.)
xr[2],yr[2] = offset_curve(ax, xr[0],yr[0], lw)
xr[3],yr[3] = offset_curve(ax, xr[1],yr[1], -lw)
xr[4],yr[4] = offset_curve(ax, xr[2],yr[2], lw)
xr[5],yr[5] = offset_curve(ax, xr[3],yr[3], -lw)
for i in range(6):
lines[i].set_data(xr[i], yr[i])
plot_rainbow()
fig.canvas.mpl_connect("resize_event", plot_rainbow)
fig.canvas.mpl_connect("button_release_event", plot_rainbow)
plt.savefig(__file__+".png", dpi=dpi)
plt.show()
Method2
为了避免重叠行,必须使用更复杂的解决方案。可以首先偏移垂直于它所在的两个线段的每个点(下图中的绿点)。然后计算通过这些偏移点的直线并找到它们的交点。

一种特殊情况是两个后续线段的斜率相等。必须注意这一点(下面代码中的eps)。
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
dpi = 100
def intersect(p1, p2, q1, q2, eps=1.e-10):
""" given two lines, first through points pn, second through qn,
find the intersection """
x1 = p1[0]; y1 = p1[1]; x2 = p2[0]; y2 = p2[1]
x3 = q1[0]; y3 = q1[1]; x4 = q2[0]; y4 = q2[1]
nomX = ((x1*y2-y1*x2)*(x3-x4)- (x1-x2)*(x3*y4-y3*x4))
denom = float( (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4) )
nomY = (x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)
if np.abs(denom) < eps:
#print "intersection undefined", p1
return np.array( p1 )
else:
return np.array( [ nomX/denom , nomY/denom ])
def offset(x,y, o, eps=1.e-10):
""" Offset coordinates given by array x,y by o """
X = np.c_[x,y].T
m = np.array([[0,-1],[1,0]])
S = X[:,1:]-X[:,:-1]
R = np.dot(m, S)
norm = np.sqrt(R[0,:]**2+R[1,:]**2) / o
On = R/norm
Outa = On+X[:,1:]
Outb = On+X[:,:-1]
G = np.zeros_like(X)
for i in xrange(0, len(X[0,:])-2):
p = intersect(Outa[:,i], Outb[:,i], Outa[:,i+1], Outb[:,i+1], eps=eps)
G[:,i+1] = p
G[:,0] = Outb[:,0]
G[:,-1] = Outa[:,-1]
return G[0,:], G[1,:]
def offset_curve(ax, x,y, o, eps=1.e-10):
""" Offset array x,y in data coordinates
by o in points """
trans = ax.transData.transform
inv = ax.transData.inverted().transform
X = np.c_[x,y]
Xt = trans(X)
xto, yto = offset(Xt[:,0],Xt[:,1],o*dpi/72., eps=eps )
Xto = np.c_[xto, yto]
Xo = inv(Xto)
return Xo[:,0], Xo[:,1]
# some single points
y = np.array([1,1,2,0,3,2,1.,4,3]) *1.e9
x = np.arange(len(y))
x[3]=x[4]
#or try a sinus
#x = np.linspace(0,9)
#y=np.sin(x)*x/3.
fig, ax=plt.subplots(figsize=(4,2.5), dpi=dpi)
cols = ["r", "b"]
lw = 11.
lines = []
for i in range(len(cols)):
l, = plt.plot(x,y, lw=lw, color=cols[i], solid_joinstyle="miter")
lines.append(l)
def plot_rainbow(event=None):
xr = range(2); yr = range(2);
xr[0],yr[0] = offset_curve(ax, x,y, lw/2.)
xr[1],yr[1] = offset_curve(ax, x,y, -lw/2.)
for i in range(2):
lines[i].set_data(xr[i], yr[i])
plot_rainbow()
fig.canvas.mpl_connect("resize_event", plot_rainbow)
fig.canvas.mpl_connect("button_release_event", plot_rainbow)
plt.show()

请注意,只要直线之间的偏移量小于直线上后续点之间的距离,此方法就可以很好地工作。否则,方法1可能更适合。
发布于 2017-02-11 03:52:42
我能想到的最好的办法就是获取你的数据,生成一系列小的偏移量,然后使用fill_between来制作你喜欢的任何颜色的带子。
我写了一个函数来做这件事。我不知道你想画的是什么形状,所以这可能对你有用,也可能对你没用。我在抛物线上测试了它,得到了不错的结果。您还可以使用颜色列表。
def rainbow_plot(x, y, spacing=0.1):
fig, ax = plt.subplots()
colors = ['red', 'yellow', 'green', 'cyan','blue']
top = max(y)
lines = []
for i in range(len(colors)+1):
newline_data = y - top*spacing*i
lines.append(newline_data)
for i, c in enumerate(colors):
ax.fill_between(x, lines[i], lines[i+1], facecolor=c)
return fig, ax
x = np.linspace(0,1,51)
y = 1-(x-0.5)**2
rainbow_plot(x,y)

https://stackoverflow.com/questions/42165631
复制相似问题