Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在matplotlib中绘制渐变色线?_Python_Matplotlib_Gradient - Fatal编程技术网

Python 如何在matplotlib中绘制渐变色线?

Python 如何在matplotlib中绘制渐变色线?,python,matplotlib,gradient,Python,Matplotlib,Gradient,为了以一般形式陈述它,我正在寻找一种方法,使用matplotlib将几个点与渐变色线连接起来,但我在任何地方都找不到它。 更具体地说,我用一条单色线绘制了一个二维随机游动。但是,由于这些点有一个相关的序列,我想看一下图,看看数据移动到了哪里。一条渐变色的线就可以了。或者是一条透明度逐渐变化的线 我只是想改进我的数据的可视化。看看这张由R的ggplot2软件包制作的漂亮图片。我正在matplotlib中寻找同样的图片。谢谢 我最近用类似的请求回答了一个问题()。在那里,我展示了你可以将你需要的颜色

为了以一般形式陈述它,我正在寻找一种方法,使用matplotlib将几个点与渐变色线连接起来,但我在任何地方都找不到它。 更具体地说,我用一条单色线绘制了一个二维随机游动。但是,由于这些点有一个相关的序列,我想看一下图,看看数据移动到了哪里。一条渐变色的线就可以了。或者是一条透明度逐渐变化的线

我只是想改进我的数据的可视化。看看这张由R的ggplot2软件包制作的漂亮图片。我正在matplotlib中寻找同样的图片。谢谢


我最近用类似的请求回答了一个问题()。在那里,我展示了你可以将你需要的颜色循环映射到一个颜色映射图上。可以使用相同的步骤为每对点获取特定的颜色

您应该仔细选择颜色贴图,因为如果颜色贴图是彩色的,则线条上的颜色过渡可能会非常激烈

或者,可以更改每个线段的alpha,范围从0到1

下面的代码示例中包含了一个例程(
highResPoints
),用于扩展随机游动的点数,因为如果点数太少,则过渡可能会非常剧烈。这段代码的灵感来自我最近提供的另一个答案:

将numpy导入为np
将matplotlib.pyplot作为plt导入
def高响应点(x,y,系数=10):
'''
取两个向量中列出的点,并以更高的值返回
结果。创建至少因子*len(x)个新点,包括
原始点和中间间隔的点。
以元组(x,y)的形式返回新的x和y数组。
'''
#r是点对之间的跨距
r=[0]
对于范围(1,len(x))中的i:
dx=x[i]-x[i-1]
dy=y[i]-y[i-1]
r、 追加(np.sqrt(dx*dx+dy*dy))
r=np.数组(r)
#rtot是r的累积和,用于节省时间
rtot=[]
对于范围内的i(len(r)):
rtot.append(r[0:i].sum())
rtot.append(r.sum())
dr=rtot[-1]/(NPOINTS*RESFACT-1)
xmod=[x[0]]
ymod=[y[0]]
rPos=0#沿走时数据上的当前点
rcount=1
当RPOrtot[rcount+1]:
RPO=rtot[rcount+1]
rcount+=1
如果rcount>rtot[-1]:
打破
返回xmod,ymod
#常数
NPOINTS=10
“蓝色”
RESFACT=10
MAP='winter'#仔细选择,否则颜色过渡将不会出现模糊
#创建随机数据
np.随机种子(101)
x=np.random.rand(NPOINTS)
y=np.random.rand(NPOINTS)
图=plt.图()
ax1=图add_子图(221)#常规分辨率彩色地图
ax2=图add_子图(222)#常规分辨率α
ax3=图添加_子图(223)#高分辨率彩色地图
ax4=图add_子图(224)#高分辨率alpha
#选择颜色贴图,循环颜色,并将其指定给颜色
#循环。您需要NPOINTS-1颜色,因为您将绘制那么多线
#在两人之间。换句话说,您的行不是循环的,因此
#从头到尾没有一行
cm=plt.get_cmap(地图)
ax1.为范围内的i(NPOINTS-1)]设置颜色循环([cm(1.*i/(NPOINTS-1))
对于范围内的i(NPOINTS-1):
ax1.绘图(x[i:i+2],y[i:i+2])
文本(.05,1.05,'Reg.Res-Color Map')
ax1.set_ylim(0,1.2)
#方法相同,但颜色和颜色固定
#alpha是在NPOINTS步长中从0到1的比例
对于范围内的i(NPOINTS-1):
ax2.绘图(x[i:i+2],y[i:i+2],alpha=float(i)/(NPOINTS-1),color=color)
ax2.text(.05,1.05,'Reg.Res-alpha')
ax2.set_ylim(0,1.2)
#获取更高分辨率的数据
xHiRes,yHiRes=高响应点(x,y,RESFACT)
npointsHiRes=len(xHiRes)
cm=plt.get_cmap(地图)
ax3.设置颜色循环([cm(1.*i/(npointsHiRes-1))
对于范围内的i(npointsHiRes-1)])
对于范围内的i(npointsHiRes-1):
ax3.绘图(xHiRes[i:i+2],yHiRes[i:i+2])
文本(.05,1.05,'Hi Res-Color Map')
ax3.set_ylim(0,1.2)
对于范围内的i(npointsHiRes-1):
ax4.绘图(xHiRes[i:i+2],yHiRes[i:i+2],
α=浮点数(i)/(npointsHiRes-1),
颜色=颜色)
文本(.05,1.05,'High Res-alpha')
ax4.set_ylim(0,1.2)
图savefig('gradColorLine.png'))
plt.show()
此图显示了四种情况:


请注意,如果您有许多点,为每个线段调用
plt.plot
可能会非常慢。使用LineCollection对象更有效

使用,您可以执行以下操作:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.collections as mcoll
import matplotlib.path as mpath

def colorline(
    x, y, z=None, cmap=plt.get_cmap('copper'), norm=plt.Normalize(0.0, 1.0),
        linewidth=3, alpha=1.0):
    """
    http://nbviewer.ipython.org/github/dpsanders/matplotlib-examples/blob/master/colorline.ipynb
    http://matplotlib.org/examples/pylab_examples/multicolored_line.html
    Plot a colored line with coordinates x and y
    Optionally specify colors in the array z
    Optionally specify a colormap, a norm function and a line width
    """

    # Default colors equally spaced on [0,1]:
    if z is None:
        z = np.linspace(0.0, 1.0, len(x))

    # Special case if a single number:
    if not hasattr(z, "__iter__"):  # to check for numerical input -- this is a hack
        z = np.array([z])

    z = np.asarray(z)

    segments = make_segments(x, y)
    lc = mcoll.LineCollection(segments, array=z, cmap=cmap, norm=norm,
                              linewidth=linewidth, alpha=alpha)

    ax = plt.gca()
    ax.add_collection(lc)

    return lc


def make_segments(x, y):
    """
    Create list of line segments from x and y coordinates, in the correct format
    for LineCollection: an array of the form numlines x (points per line) x 2 (x
    and y) array
    """

    points = np.array([x, y]).T.reshape(-1, 1, 2)
    segments = np.concatenate([points[:-1], points[1:]], axis=1)
    return segments

N = 10
np.random.seed(101)
x = np.random.rand(N)
y = np.random.rand(N)
fig, ax = plt.subplots()

path = mpath.Path(np.column_stack([x, y]))
verts = path.interpolated(steps=3).vertices
x, y = verts[:, 0], verts[:, 1]
z = np.linspace(0, 1, len(x))
colorline(x, y, z, cmap=plt.get_cmap('jet'), linewidth=2)

plt.show()
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.collections as mcoll
import matplotlib.path as mpath

x = np.arange(-8, 4, 0.01)
y = 1 + 0.5 * x**2

MAP = 'jet'
NPOINTS = len(x)

fig = plt.figure()
ax1 = fig.add_subplot(111) 
cm = plt.get_cmap(MAP)
for i in range(10):
    ax1.set_color_cycle([cm(1.0*i/(NPOINTS-1)) for i in range(NPOINTS-1)])
    for i in range(NPOINTS-1):
        plt.plot(x[i:i+2],y[i:i+2])

plt.title('Inner minimization', fontsize=25)
plt.xlabel(r'Friction torque $[Nm]$', fontsize=25)
plt.ylabel(r'Accelerations energy $[\frac{Nm}{s^2}]$', fontsize=25)
plt.show() # Show the figure

对于注释来说太长了,所以只想确认
LineCollection
比for loop over line subsegments快得多

import numpy as np
import matplotlib.pyplot as plt

def _get_perp_line(current_seg, out_of_page, linewidth):
    perp = np.cross(current_seg, out_of_page)[0:2]
    perp_unit = _get_unit_vector(perp)
    current_seg_perp_line = perp_unit*linewidth
    return current_seg_perp_line

def _get_unit_vector(vector):
    vector_size = (vector[0]**2 + vector[1]**2)**0.5
    vector_unit = vector / vector_size
    return vector_unit[0:2]

def colored_line(x, y, z=None, line_width=1, MAP='jet'):
    # use pcolormesh to make interpolated rectangles
    num_pts = len(x)
    [xs, ys, zs] = [
        np.zeros((num_pts,2)),
        np.zeros((num_pts,2)),
        np.zeros((num_pts,2))
    ]

    dist = 0
    out_of_page = [0, 0, 1]
    for i in range(num_pts):
        # set the colors and the x,y locations of the source line
        xs[i][0] = x[i]
        ys[i][0] = y[i]
        if i > 0:
            x_delta =  x[i] - x[i-1]
            y_delta =  y[i] - y[i-1]
            seg_length = (x_delta**2 + y_delta**2)**0.5
            dist += seg_length
            zs[i] = [dist, dist]

        # define the offset perpendicular points
        if i == num_pts - 1:
            current_seg = [x[i]-x[i-1], y[i]-y[i-1], 0]
        else:
            current_seg = [x[i+1]-x[i], y[i+1]-y[i], 0]
        current_seg_perp = _get_perp_line(
            current_seg, out_of_page, line_width)
        if i == 0 or i == num_pts - 1:
            xs[i][1] = xs[i][0] + current_seg_perp[0]
            ys[i][1] = ys[i][0] + current_seg_perp[1]
            continue
        current_pt = [x[i], y[i]]
        current_seg_unit = _get_unit_vector(current_seg)
        previous_seg = [x[i]-x[i-1], y[i]-y[i-1], 0]
        previous_seg_perp = _get_perp_line(
            previous_seg, out_of_page, line_width)
        previous_seg_unit = _get_unit_vector(previous_seg)
        # current_pt + previous_seg_perp + scalar * previous_seg_unit =
        # current_pt + current_seg_perp - scalar * current_seg_unit =
        scalar = (
            (current_seg_perp - previous_seg_perp) /
            (previous_seg_unit + current_seg_unit)
        )
        new_pt = current_pt + previous_seg_perp + scalar[0] * previous_seg_unit
        xs[i][1] = new_pt[0]
        ys[i][1] = new_pt[1]

    fig, ax = plt.subplots()
    cm = plt.get_cmap(MAP)
    ax.pcolormesh(xs, ys, zs, shading='gouraud', cmap=cm)
    plt.axis('scaled')
    plt.show()

# create random data
N = 10
np.random.seed(101)
x = np.random.rand(N)
y = np.random.rand(N)
colored_line(x, y, line_width = .01)
LineCollection方法在我的手中要快得多

# Setup
x = np.linspace(0,4*np.pi,1000)
y = np.sin(x)
MAP = 'cubehelix'
NPOINTS = len(x)
我们将根据上面的LineCollection方法测试迭代打印

%%timeit -n1 -r1
# Using IPython notebook timing magics
fig = plt.figure()
ax1 = fig.add_subplot(111) # regular resolution color map
cm = plt.get_cmap(MAP)
for i in range(10):
    ax1.set_color_cycle([cm(1.*i/(NPOINTS-1)) for i in range(NPOINTS-1)])
    for i in range(NPOINTS-1):
        plt.plot(x[i:i+2],y[i:i+2])
1个循环,每个循环最好1:13.4秒

%%timeit -n1 -r1 
fig = plt.figure()
ax1 = fig.add_subplot(111) # regular resolution color map
for i in range(10):
    colorline(x,y,cmap='cubehelix', linewidth=1)
1个循环,每个循环1:532毫秒的最佳时间

%%timeit -n1 -r1 
fig = plt.figure()
ax1 = fig.add_subplot(111) # regular resolution color map
for i in range(10):
    colorline(x,y,cmap='cubehelix', linewidth=1)

如果你想要一个平滑的渐变,并且你只有几个点,那么按照当前选择的答案对你的线条进行上采样以获得更好的颜色渐变仍然是一个好主意。

这是我使用pcolormesh的不同解决方案 每个线段都使用四边形绘制,四边形在每一端的颜色之间插值。因此,它实际上是在不添加额外线段的情况下对颜色进行插值

import numpy as np
import matplotlib.pyplot as plt

def _get_perp_line(current_seg, out_of_page, linewidth):
    perp = np.cross(current_seg, out_of_page)[0:2]
    perp_unit = _get_unit_vector(perp)
    current_seg_perp_line = perp_unit*linewidth
    return current_seg_perp_line

def _get_unit_vector(vector):
    vector_size = (vector[0]**2 + vector[1]**2)**0.5
    vector_unit = vector / vector_size
    return vector_unit[0:2]

def colored_line(x, y, z=None, line_width=1, MAP='jet'):
    # use pcolormesh to make interpolated rectangles
    num_pts = len(x)
    [xs, ys, zs] = [
        np.zeros((num_pts,2)),
        np.zeros((num_pts,2)),
        np.zeros((num_pts,2))
    ]

    dist = 0
    out_of_page = [0, 0, 1]
    for i in range(num_pts):
        # set the colors and the x,y locations of the source line
        xs[i][0] = x[i]
        ys[i][0] = y[i]
        if i > 0:
            x_delta =  x[i] - x[i-1]
            y_delta =  y[i] - y[i-1]
            seg_length = (x_delta**2 + y_delta**2)**0.5
            dist += seg_length
            zs[i] = [dist, dist]

        # define the offset perpendicular points
        if i == num_pts - 1:
            current_seg = [x[i]-x[i-1], y[i]-y[i-1], 0]
        else:
            current_seg = [x[i+1]-x[i], y[i+1]-y[i], 0]
        current_seg_perp = _get_perp_line(
            current_seg, out_of_page, line_width)
        if i == 0 or i == num_pts - 1:
            xs[i][1] = xs[i][0] + current_seg_perp[0]
            ys[i][1] = ys[i][0] + current_seg_perp[1]
            continue
        current_pt = [x[i], y[i]]
        current_seg_unit = _get_unit_vector(current_seg)
        previous_seg = [x[i]-x[i-1], y[i]-y[i-1], 0]
        previous_seg_perp = _get_perp_line(
            previous_seg, out_of_page, line_width)
        previous_seg_unit = _get_unit_vector(previous_seg)
        # current_pt + previous_seg_perp + scalar * previous_seg_unit =
        # current_pt + current_seg_perp - scalar * current_seg_unit =
        scalar = (
            (current_seg_perp - previous_seg_perp) /
            (previous_seg_unit + current_seg_unit)
        )
        new_pt = current_pt + previous_seg_perp + scalar[0] * previous_seg_unit
        xs[i][1] = new_pt[0]
        ys[i][1] = new_pt[1]

    fig, ax = plt.subplots()
    cm = plt.get_cmap(MAP)
    ax.pcolormesh(xs, ys, zs, shading='gouraud', cmap=cm)
    plt.axis('scaled')
    plt.show()

# create random data
N = 10
np.random.seed(101)
x = np.random.rand(N)
y = np.random.rand(N)
colored_line(x, y, line_width = .01)

我使用@alexbw代码绘制抛物线。它工作得很好。我可以更改功能的颜色集。为了计算,我花了大约1分钟30秒。我用的是英特尔i5,图形2gb,8gb内存

代码如下:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.collections as mcoll
import matplotlib.path as mpath

def colorline(
    x, y, z=None, cmap=plt.get_cmap('copper'), norm=plt.Normalize(0.0, 1.0),
        linewidth=3, alpha=1.0):
    """
    http://nbviewer.ipython.org/github/dpsanders/matplotlib-examples/blob/master/colorline.ipynb
    http://matplotlib.org/examples/pylab_examples/multicolored_line.html
    Plot a colored line with coordinates x and y
    Optionally specify colors in the array z
    Optionally specify a colormap, a norm function and a line width
    """

    # Default colors equally spaced on [0,1]:
    if z is None:
        z = np.linspace(0.0, 1.0, len(x))

    # Special case if a single number:
    if not hasattr(z, "__iter__"):  # to check for numerical input -- this is a hack
        z = np.array([z])

    z = np.asarray(z)

    segments = make_segments(x, y)
    lc = mcoll.LineCollection(segments, array=z, cmap=cmap, norm=norm,
                              linewidth=linewidth, alpha=alpha)

    ax = plt.gca()
    ax.add_collection(lc)

    return lc


def make_segments(x, y):
    """
    Create list of line segments from x and y coordinates, in the correct format
    for LineCollection: an array of the form numlines x (points per line) x 2 (x
    and y) array
    """

    points = np.array([x, y]).T.reshape(-1, 1, 2)
    segments = np.concatenate([points[:-1], points[1:]], axis=1)
    return segments

N = 10
np.random.seed(101)
x = np.random.rand(N)
y = np.random.rand(N)
fig, ax = plt.subplots()

path = mpath.Path(np.column_stack([x, y]))
verts = path.interpolated(steps=3).vertices
x, y = verts[:, 0], verts[:, 1]
z = np.linspace(0, 1, len(x))
colorline(x, y, z, cmap=plt.get_cmap('jet'), linewidth=2)

plt.show()
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.collections as mcoll
import matplotlib.path as mpath

x = np.arange(-8, 4, 0.01)
y = 1 + 0.5 * x**2

MAP = 'jet'
NPOINTS = len(x)

fig = plt.figure()
ax1 = fig.add_subplot(111) 
cm = plt.get_cmap(MAP)
for i in range(10):
    ax1.set_color_cycle([cm(1.0*i/(NPOINTS-1)) for i in range(NPOINTS-1)])
    for i in range(NPOINTS-1):
        plt.plot(x[i:i+2],y[i:i+2])

plt.title('Inner minimization', fontsize=25)
plt.xlabel(r'Friction torque $[Nm]$', fontsize=25)
plt.ylabel(r'Accelerations energy $[\frac{Nm}{s^2}]$', fontsize=25)
plt.show() # Show the figure
结果是:


基于Yann的回复,我