fin*_*oot 2 python plot image colors matplotlib
我想用一种颜色开始曲线,然后逐渐融入另一种颜色,直到结束。我的 MCVE 中的以下功能可以工作,但是肯定有我还没有发现的更好的方法吗?!
import numpy as np
import matplotlib.pyplot as plt
def colorlist(color1, color2, num):
"""Generate list of num colors blending from color1 to color2"""
result = [np.array(color1), np.array(color2)]
while len(result) < num:
temp = [result[0]]
for i in range(len(result)-1):
temp.append(np.sqrt((result[i]**2+result[i+1]**2)/2))
temp.append(result[i+1])
result = temp
indices = np.linspace(0, len(result)-1, num).round().astype(int)
return [result[i] for i in indices]
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
colors = colorlist((1, 0, 0), (0, 0, 1), len(x))
for i in range(len(x)-1):
xi = x[i:i+1+1]
yi = y[i:i+1+1]
ci = colors[i]
plt.plot(xi, yi, color=ci, linestyle='solid', linewidth='10')
plt.show()
Run Code Online (Sandbox Code Playgroud)
不确定“更好的方法”指的是什么。代码更少、绘制速度更快的解决方案是将 LineCollection 与颜色图一起使用。
颜色图可以由两种颜色定义,中间的任何颜色都会自动插值。
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", [(1, 0, 0), (0, 0, 1)])
Run Code Online (Sandbox Code Playgroud)
LineCollection 可用于一次绘制多条线。作为一个 ScalarMappable,它可以使用颜色图根据某个数组对每条线进行不同的着色 - 在这种情况下,人们可能只为此目的使用 x 值。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import LinearSegmentedColormap
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
cmap = LinearSegmentedColormap.from_list("", [(1, 0, 0), (0, 0, 1)])
points = np.array([x, y]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, linewidth=10)
lc.set_array(x)
plt.gca().add_collection(lc)
plt.gca().autoscale()
plt.show()
Run Code Online (Sandbox Code Playgroud)
如图所示,该解决方案的缺点是各个线路没有很好地连接。
因此,为了规避这一点,可以绘制这些点重叠,使用
segments = np.concatenate([points[:-2],points[1:-1], points[2:]], axis=1)
Run Code Online (Sandbox Code Playgroud)
要获得与问题中相同的颜色,您可以使用相同的函数为 LineCollection 创建颜色图中使用的颜色。如果目的是简化此函数,您可以直接将这些值计算为通道中色差的平方根。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import LinearSegmentedColormap
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
def colorlist2(c1, c2, num):
l = np.linspace(0,1,num)
a = np.abs(np.array(c1)-np.array(c2))
m = np.min([c1,c2], axis=0)
s = np.sign(np.array(c2)-np.array(c1)).astype(int)
s[s==0] =1
r = np.sqrt(np.c_[(l*a[0]+m[0])[::s[0]],(l*a[1]+m[1])[::s[1]],(l*a[2]+m[2])[::s[2]]])
return r
cmap = LinearSegmentedColormap.from_list("", colorlist2((1, 0, 0), (0, 0, 1),100))
points = np.array([x, y]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-2],points[1:-1], points[2:]], axis=1)
lc = LineCollection(segments, cmap=cmap, linewidth=10)
lc.set_array(x)
plt.gca().add_collection(lc)
plt.gca().autoscale()
plt.show()
Run Code Online (Sandbox Code Playgroud)