You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据传球次数条件设置Matplotlib点间折线颜色

解决方案

一、实现折线颜色随传球次数(Count)变化

要让折线颜色随Count值增大偏向红色,你可以直接将upd_passes['Count']加入循环的zip对象,同时借助matplotlib的颜色映射与归一化工具,把Count值映射到对应颜色区间:

修改后的折线绘制代码:

# 对Count值做归一化,适配颜色映射的0-1区间
norm = plt.Normalize(upd_passes['Count'].min(), upd_passes['Count'].max())
# 选择从蓝到红的渐变配色(改用'Reds'可实现纯红色系渐变)
cmap = plt.get_cmap('coolwarm')

# Lines between points:
for x0, y0, x1, y1, count in zip(x, y, xr, yr, upd_passes['Count']):
    # 根据当前Count值获取对应颜色
    line_color = cmap(norm(count))
    plt.plot((x0, x1), (y0, y1), '-', color=line_color, linewidth=3, alpha=0.6, zorder=1)

这里移除了原代码中的-ro(无需给每条折线添加红色圆点),调整alpha让颜色对比更明显。通过norm将Count值缩放到0-1范围,再用cmap匹配对应颜色,实现Count越大颜色越偏红的效果。

二、简化DataFrame合并操作

原代码在数据合并环节存在冗余,可通过链式调用+直接重命名列的方式优化,避免重复创建中间DataFrame:

优化后的upd_passes构建代码:

# 链式合并所有数据,减少中间变量
upd_passes = (pd.merge(players, passes, on='Player_id')
              .groupby(['Player_id', 'Name', 'Receiver_id'])
              .size()
              .reset_index(name='Count')  # 直接命名统计列,无需后续修改columns
              .merge(avg_positions.rename(columns={'Name': 'Player_name', 
                                                   'avg_pos_x': 'Player_x', 
                                                   'avg_pos_y': 'Player_y'}),
                     on='Player_id')
              .merge(avg_positions.rename(columns={'Player_id': 'Receiver_id',
                                                   'avg_pos_x': 'Receiver_x',
                                                   'avg_pos_y': 'Receiver_y'}),
                     on='Receiver_id')
              .merge(players.rename(columns={'Player_id': 'Receiver_id',
                                             'Name': 'Receiver_name'}),
                     on='Receiver_id')
              .sort_values('Player_id')
              .reset_index(drop=True))

# 按需筛选保留列(不需要可省略)
upd_passes = upd_passes[['Player_id', 'Player_name', 'Player_x', 'Player_y', 
                         'Receiver_id', 'Receiver_name', 'Receiver_x', 'Receiver_y', 'Count']]

此方式省去了创建avg_positions2和receivers的步骤,直接在merge时重命名列,链式调用让代码更简洁紧凑。

完整修改后的代码

整合上述优化点后的完整代码如下:

import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.patheffects as PathEffects

pd.set_option('display.width', 400)
pd.set_option('display.max_columns', 10)

players = pd.DataFrame([[1, 'Player 1'],
                         [2, 'Player 2'],
                         [3, 'Player 3'],
                         [4, 'Player 4'],
                         [5, 'Player 5'],
                         [6, 'Player 6'],
                         [7, 'Player 7']], columns=['Player_id', 'Name'])

avg_positions = pd.DataFrame([[1, 15, 34],
                              [2, 35, 48],
                              [3, 58, 27],
                              [4, 62, 55],
                              [5, 52, 40],
                              [6, 69, 31],
                              [7, 27, 9]], columns=['Player_id', 'avg_pos_x', 'avg_pos_y'])

passes = pd.DataFrame([[1, 2],
                       [1, 2],
                       [1, 3],
                       [2, 1],
                       [2, 5],
                       [3, 6],
                       [6, 1],
                       [4, 2],
                       [4, 2],
                       [5, 7],
                       [6, 2],
                       [7, 3],
                       [7, 3],
                       [7, 3],
                       [7, 1]], columns=['Player_id', 'Receiver_id'])

plt.style.use('_mpl-gallery')

# 优化后的DataFrame合并逻辑
upd_passes = (pd.merge(players, passes, on='Player_id')
              .groupby(['Player_id', 'Name', 'Receiver_id'])
              .size()
              .reset_index(name='Count')
              .merge(avg_positions.rename(columns={'Name': 'Player_name', 
                                                   'avg_pos_x': 'Player_x', 
                                                   'avg_pos_y': 'Player_y'}),
                     on='Player_id')
              .merge(avg_positions.rename(columns={'Player_id': 'Receiver_id',
                                                   'avg_pos_x': 'Receiver_x',
                                                   'avg_pos_y': 'Receiver_y'}),
                     on='Receiver_id')
              .merge(players.rename(columns={'Player_id': 'Receiver_id',
                                             'Name': 'Receiver_name'}),
                     on='Receiver_id')
              .sort_values('Player_id')
              .reset_index(drop=True))

upd_passes = upd_passes[['Player_id', 'Player_name', 'Player_x', 'Player_y', 
                         'Receiver_id', 'Receiver_name', 'Receiver_x', 'Receiver_y', 'Count']]
print(upd_passes)

passes_count = passes.groupby('Player_id')['Player_id'].count()

# Player (dots) coordinates:
xa = avg_positions.avg_pos_y
ya = avg_positions.avg_pos_x

# Player's coordinates:
x = upd_passes.Player_y
y = upd_passes.Player_x

# Receiver's coordinates:
xr = upd_passes.Receiver_y
yr = upd_passes.Receiver_x

# Point sizes and colors:
sizes = passes_count * 80
colors = passes_count

# Define player names for text annotations:
names = players.Name

# plot
fig, ax = plt.subplots()

ax.scatter(xa, ya, s=sizes, c=colors, vmin=0, vmax=5, cmap=plt.get_cmap('viridis'), zorder=2)

# Text above points:
for i, txt in enumerate(names):
    ax.annotate(txt, xy=(xa[i], ya[i]), xytext=(xa[i]-3, ya[i]+2), fontsize=9, color='black',
                path_effects=[PathEffects.withStroke(linewidth=3, foreground="w")])

# 处理折线颜色逻辑
norm = plt.Normalize(upd_passes['Count'].min(), upd_passes['Count'].max())
cmap = plt.get_cmap('coolwarm')

# Lines between points:
for x0, y0, x1, y1, count in zip(x, y, xr, yr, upd_passes['Count']):
    line_color = cmap(norm(count))
    plt.plot((x0, x1), (y0, y1), '-', color=line_color, linewidth=3, alpha=0.6, zorder=1)

fig.set_size_inches(5, 5)
plt.show()

内容的提问来源于stack exchange,提问作者muted_buddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:27:12