简体   繁体   English

使用 matplotlib cmap 在子图之间填充

[英]Fill between subplots with matplotlib cmap

I have 2 line plots on the same figure, plotted from pandas dataframes.我在同一张图上有 2 条线图,是从熊猫数据框绘制的。

I want to fill between them with a gradient/colour map of sorts.我想在它们之间填充各种渐变/颜色图。

I understand I can do this with a cmap, only it will not work for me (see code below).我知道我可以用 cmap 做到这一点,只是它对我不起作用(见下面的代码)。

General example I found are filling between x axis and line, i do not want that and also i am interested in simplest solution possible for this as i am a begginer at this and complicated, though maybe better code will just make it more confusing honestly.我发现的一般示例是在 x 轴和线之间填充,我不想要那个,而且我对可能的最简单解决方案感兴趣,因为我是这方面的初学者并且很复杂,尽管也许更好的代码只会让它更老实说更混乱。

Code for which fill is plain blue:填充为纯蓝色的代码:

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()

EDIT/UPDATE: DATA EXAMPLE other is ALWAYS >= other2编辑/更新:数据示例 other 总是 >= 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

Final graph example:最终图示例: 例子

I would like the fill to go from orange on top to blue at the bottom我希望填充从顶部的橙色变为底部的蓝色

Edit编辑

In response to the edited question, here is an alternative approach which does the gradient vertically but doesn't use imshow .为了回应编辑的问题,这里有一种替代方法,它垂直渐变但不使用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()

在此处输入图片说明

The idea here being similar to that in my original answer, except the trapezoids are divided into nc pieces and each piece is colored separately.这里的想法与我原来的答案相似,除了梯形被分成nc块,每块都单独着色。 This has the advantage of scaling correctly for varying y1[ii] , y2[ii] distances, as shown in this comparison,这具有针对变化的y1[ii]y2[ii]距离正确缩放的优点,如本比较所示,

在此处输入图片说明

It does, however, have the disadvantages of being much, much slower than imshow or the horizontal gradient method and of being unable to handle 'crossing' correctly.它,然而,有被许多缺点,远远低于imshow或水平梯度方法和存在无法处理“交叉”正确。

The code to generate the second image in the above comparison:上面比较中生成第二张图片的代码:

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

x = np.linspace(0, 10, n)
y1 = [-50.0]
y2 = [50.0]
for ii in range(1, n):
    y1.append(y1[ii-1] + (np.random.random()-0.2)*3)
    y2.append(y2[ii-1] + (np.random.random()-0.5)*3)
y1 = np.array(y1)
y2 = np.array(y2)

verts = np.vstack([np.stack([x, y1], 1), np.stack([np.flip(x), np.flip(y2)], 1)])
path = Path(verts)

patch = patches.PathPatch(path, facecolor='k', lw=2, alpha=0.0)
plt.gca().add_patch(patch)

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

Original原来的

This is a bit of a hack, partly based on the answers in this question .这有点骇人听闻,部分基于此问题中的答案。 It does seem to work fairly well but works best with higher density along the x axis.它似乎工作得相当好,但在沿x轴密度较高的情况下效果最佳。 The idea is to call fill_between separately for each trapezoid corresponding to x pairs, [x[ii], x[ii+1]] .这个想法是为每个对应于x[x[ii], x[ii+1]]梯形分别调用fill_between Here is a complete example using some generated data这是一个使用一些生成数据的完整示例

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()

在此处输入图片说明

This can be generalized to a 2 dimensional color grid but would require non-trivial modification这可以推广到二维颜色网格,但需要进行非平凡的修改

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM