使用matplotlib cmap在子批次之间填充

2024-10-04 01:26:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我在同一个图上画了两条线,是从熊猫数据框画出来的。你知道吗

我想在它们之间填充一个渐变/彩色地图。你知道吗

我知道我可以用cmap来做这件事,但它对我不起作用(见下面的代码)。你知道吗

我发现一般的例子是在x轴和直线之间填充,我不想这样,而且我对最简单的解决方案也感兴趣,因为我是一个乞丐在这个和复杂的,虽然也许更好的代码只会让它更混乱诚实。你知道吗

填充为纯蓝色的代码:

import matplotlib.pyplot as plt
import pandas as pd

ax = plt.gca()

df0.plot(kind='line', x='something', y='other', color='orange', ax=ax, legend=False, figsize=(20,10))
df1.plot(kind='line', x='something', y='other2', color='c', ax=ax, legend=False, figsize=(20,10))

ax.fill_between(x=df0['daysInAYear'], y1=df0['other'], y2 = df1['other2'], alpha=0.2, cmap=plt.cm.get_cmap("winter"))
plt.show()

编辑/更新:数据示例 其他总是>;=other2

other  other2  something (same for both)
15.6    -16.0      1
13.9    -26.7      2
13.3    -26.7      3
10.6    -26.1      4
12.8    -15.0      5

最后一个图形示例: example

我想把馅料从上面的橙色调成下面的蓝色


Tags: 数据代码importplotaslinepltax
2条回答

让我们试试这样的方法:

import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches

df = pd.DataFrame({'x':np.arange(10),'y':np.arange(10,20), 'y2':np.arange(100,110)})

ax = df.plot('x','y')
df.plot('x','y2', ax=ax)
verts = np.vstack([df[['x','y']].to_numpy(), df[::-1].loc[:,['x','y2']].to_numpy()])
path = Path(verts)

patch = patches.PathPatch(path, facecolor='k', lw=2, alpha=.3)
ax.add_patch(patch)

im = plt.imshow(np.arange(10).reshape(10,-1), cmap=plt.cm.winter, interpolation="bicubic",
                origin='upper', extent=[0,10,0,125], aspect='auto', clip_path=patch, clip_on=True)

输出:

enter image description here

编辑

为了回答编辑后的问题,这里有一种替代方法,它垂直地进行渐变,但不使用imshow。你知道吗

import matplotlib.pyplot as plt
from  matplotlib import colors, patches
import numpy as np
import pandas as pd

n = 100
nc = 100

x = np.linspace(0, np.pi*5, n)
y1 = [-50.0]
y2 = [50.0]
for ii in range(1, n):
    y1.append(y1[ii-1] + (np.random.random()-0.3)*3)
    y2.append(y2[ii-1] + (np.random.random()-0.5)*3)
y1 = np.array(y1)
y2 = np.array(y2)
z = np.linspace(0, 10, nc)
normalize = colors.Normalize(vmin=z.min(), vmax=z.max())
cmap = plt.cm.get_cmap('winter')

fig, ax = plt.subplots(1)
for ii in range(len(df['x'].values)-1):
    y = np.linspace(y1[ii], y2[ii], nc)
    yn = np.linspace(y1[ii+1], y2[ii+1], nc)
    for kk in range(nc - 1):
        p = patches.Polygon([[x[ii], y[kk]], 
                             [x[ii+1], yn[kk]], 
                             [x[ii+1], yn[kk+1]], 
                             [x[ii], y[kk+1]]], color=cmap(normalize(z[kk])))
        ax.add_patch(p)

plt.plot(x, y1, 'k-', lw=1)
plt.plot(x, y2, 'k-', lw=1)
plt.show()

enter image description here

这里的想法与我最初的答案相似,只是梯形被分成nc个部分,每个部分分别着色。这种方法的优点是可以正确地缩放不同的y1[ii]y2[ii]距离,如比较中所示

enter image description here

然而,它确实有许多缺点,imshow或水平梯度法慢得多,并且不能正确处理“交叉”。你知道吗


原始

这有点像黑客,部分基于this question中的答案。它似乎工作得相当好,但在沿x轴的密度较高时效果最好。其思想是分别为对应于x对的每个梯形fill_between调用[x[ii], x[ii+1]]。下面是一个使用一些生成的数据的完整示例

import matplotlib.pyplot as plt
from  matplotlib import colors
import numpy as np
import pandas as pd

n = 1000

X = np.linspace(0, np.pi*5, n)
Y1 = np.sin(X)
Y2 = np.cos(X)
Z = np.linspace(0, 10, n)
normalize = colors.Normalize(vmin=Z.min(), vmax=Z.max())
cmap = plt.cm.get_cmap('winter')

df = pd.DataFrame({'x': X, 'y1': Y1, 'y2': Y2, 'z': Z})
x = df['x'].values
y1 = df['y1'].values
y2 = df['y2'].values
z = df['z'].values

for ii in range(len(df['x'].values)-1):
    plt.fill_between([x[ii], x[ii+1]], [y1[ii], y1[ii+1]], 
                     [y2[ii], y2[ii+1]], color=cmap(normalize(z[ii])))

plt.plot(x, y1, 'k-', x, y2, 'k-')
plt.show()

enter image description here

这可以推广到一个二维的颜色网格,但需要非平凡的修改

相关问题 更多 >