如何在matplotlib图上叠加seaborn热图

Jam*_*es 1 python matplotlib pandas seaborn

我试图在一个足球场的 matplotlib 图上叠加一个热图。

这是由下面的代码块创建的 matplotlib 音高的图像:

在此处输入图片说明


import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.patches as plt_p
import numpy as np

def draw_pitch(ax):
    # size of the pitch is 120, 80
    #Create figure

    #Pitch Outline & Centre Line
    plt.plot([0,0],[0,80], color="black")
    plt.plot([0,120],[80,80], color="black")
    plt.plot([120,120],[80,0], color="black")
    plt.plot([120,0],[0,0], color="black")
    plt.plot([60,60],[0,80], color="black")

    #Left Penalty Area
    plt.plot([14.6,14.6],[57.8,22.2],color="black")
    plt.plot([0,14.6],[57.8,57.8],color="black")
    plt.plot([0,14.6],[22.2,22.2],color="black")

    #Right Penalty Area
    plt.plot([120,105.4],[57.8,57.8],color="black")
    plt.plot([105.4,105.4],[57.8,22.5],color="black")
    plt.plot([120, 105.4],[22.5,22.5],color="black")

    #Left 6-yard Box
    plt.plot([0,4.9],[48,48],color="black")
    plt.plot([4.9,4.9],[48,32],color="black")
    plt.plot([0,4.9],[32,32],color="black")

    #Right 6-yard Box
    plt.plot([120,115.1],[48,48],color="black")
    plt.plot([115.1,115.1],[48,32],color="black")
    plt.plot([120,115.1],[32,32],color="black")

    #Prepare Circles
    centreCircle = plt.Circle((60,40),8.1,color="black",fill=False)
    centreSpot = plt.Circle((60,40),0.71,color="black")
    leftPenSpot = plt.Circle((9.7,40),0.71,color="black")
    rightPenSpot = plt.Circle((110.3,40),0.71,color="black")

    #Draw Circles
    ax.add_patch(centreCircle)
    ax.add_patch(centreSpot)
    ax.add_patch(leftPenSpot)
    ax.add_patch(rightPenSpot)

    #Prepare Arcs
    # arguments for arc
    # x, y coordinate of centerpoint of arc
    # width, height as arc might not be circle, but oval
    # angle: degree of rotation of the shape, anti-clockwise
    # theta1, theta2, start and end location of arc in degree
    leftArc = plt_p.Arc((9.7,40),height=16.2,width=16.2,angle=0,theta1=310,theta2=50,color="black")
    rightArc = plt_p.Arc((110.3,40),height=16.2,width=16.2,angle=0,theta1=130,theta2=230,color="black")

    #Draw Arcs
    ax.add_patch(leftArc)
    ax.add_patch(rightArc)

fig=plt.figure()
fig.set_size_inches(7, 5)
ax=fig.add_subplot(1,1,1)
draw_pitch(ax)
plt.axis('off')
plt.show()
Run Code Online (Sandbox Code Playgroud)

正如之前帖子所推荐的,我尝试将 ax 参数传入 sns.heatmap() 并更改 alpha 以增加热图的透明度。然而,热图仍然覆盖了整个图形,足球场不可见。

运行以下代码时,我得到以下结果:

在此处输入图片说明

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.patches as plt_p
import numpy as np

#DUMMY DATA 
df_test = pd.DataFrame(np.array([[43.2, 22.4, 0], [-5.1,-53.2,1], [33.5,-19.2,0],
                                 [23.2, 32.4, 1], [-5.3,-53.2,1], [33.5,-69.2,0],
                                 [53.2, -42.4, 0], [-5.4,-53.2,0], [-3.5,-39.2,0],
                                 [63.2, 62.4, 1], [-52,-53.2,0], [37.5,-11.2,1],
                                 [113.2, 72.4, 0], [-34.2,-53.2,0], [42.5,-119.2,1]]),
                  columns=['x', 'y', 'outcome'])

#CREATES THE HEATMAP OVERLAY ON THE FOOTBALL PITCH
def pass_comp_map(df):
    df['x_bands'] = pd.qcut(df['x'],4,labels=False)
    df['y_bands'] = pd.qcut(df['y'],3,labels=False)
    df_pass = df[['x_bands','y_bands','outcome']]
    df_sum = df_pass.groupby(['x_bands','y_bands'], as_index=False).sum() # get total number of completed passes 
    df_count = df_pass.groupby(['x_bands','y_bands'], as_index=False).count() #get total number passes
    df_agg = pd.merge(df_sum, df_count['outcome'].to_frame(), how ='left',left_index=True,right_index=True)
    df_agg['pass_comp'] = df_agg['outcome_x'] / df_agg['outcome_y']
    data = df_agg[['x_bands','y_bands','pass_comp']]
    data_pivot = data.pivot_table(index='y_bands', columns='x_bands', values='pass_comp')
    data_pivot = data_pivot.fillna(0)

    #OVERLAY FIGIURE CREATED HERE
    fig=plt.figure()
    fig.set_size_inches(7, 5)
    ax=fig.add_subplot(1,1,1)
    draw_pitch(ax)
    plt.axis('off')
    sns.heatmap(data_pivot,cbar=False, xticklabels=False, yticklabels=False,annot=True,alpha = 0.5,ax=ax)
    plt.show()

pass_comp_map(df_test)
Run Code Online (Sandbox Code Playgroud)

如何使热图覆盖在足球场上,但足球场仍然可见?

Imp*_*est 5

正如已经评论过的,我建议不要使用 seaborn.heatmap,因为几乎不可能将其缩放到字段的大小。

如果您对您的代码没有进一步的变化,只是更换线sns.heatmap(...)通过

ax.imshow(data_pivot.values, zorder=0, aspect="auto", extent=(0,120,0,80), 
          cmap=sns.cubehelix_palette(light=1, as_cmap=True))
Run Code Online (Sandbox Code Playgroud)

情节已经看起来像

在此处输入图片说明

您仍然可以使用 alpha 或使用不同的颜色图等。要注释热图,您可以通过

scale = np.array([120,80])
ax.imshow(data_pivot.values, zorder=0, aspect="auto", extent=(0,scale[0],0,scale[1]), 
          cmap=sns.cubehelix_palette(light=1, as_cmap=True), origin="lower")
offs = np.array([scale[0]/data_pivot.values.shape[1], scale[1]/data_pivot.values.shape[0]])
for pos, val in np.ndenumerate(data_pivot.values):
    ax.annotate(f"{val:.2f}", xy=np.array(pos)[::-1]*offs+offs/2, ha="center", va="center")
ax.invert_yaxis()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明